我想在Delphi XE5中使用新的TRest组件发送推文。我正在寻找一种方法来UTF8编码包含IS0-8859-1字符的推文。下面的代码有效,但涉及代码页转换等。这是更好的方法吗?任何人吗?
procedure TTwitterApi.Send(Tweet: string);
begin
Reset;
// Encode as UTF8 within (UTF-16 Delphi) string
Tweet := EncodeAsUTF8(Tweet);
FRestRequest.Resource := '1.1/statuses/update.json';
FRestRequest.Method := rmPOST;
FRestRequest.Params.AddItem('status', Tweet, pkGETorPOST);
FRestRequest.Execute;
end;
function TTwitterApi.EncodeAsUTF8(UnicodeStr: string): string;
var
UTF8Str: AnsiString;
TempStr: RawByteString;
begin
TempStr := UTF8Encode(UnicodeStr);
SetLength(UTF8Str, Length(TempStr));
Move(TempStr[1], UTF8Str[1], Length(UTF8Str));
Result := UTF8Str;
end;
答案 0 :(得分:5)
Twitter的1.1/statuses/update.json
网址要求数据以application/x-www-form-urlencoded
格式进行编码,因此您需要将TRESTClient.ContentType
属性设置为ctAPPLICATION_X_WWW_FORM_URLENCODED
(设置为ctNone
默认情况下)。
至于UTF-8,TRESTClient
在内部使用Indy,而Indy支持使用用户指定的字符集对出站数据进行编码,但Embarcadero似乎没有将该功能添加到其TRESTClient
接口(它虽然在回答中处理字符集。我不知道为什么Embarcadero会省略这样一个重要的特征。仅仅将字符串数据编码为UTF-8(您没有正确执行,BTW)是不够的,但您还必须告诉Twitter数据已经过UTF-8编码(通过charset
属性Content-Type
REST标头),TRESTClient
不允许你这样做,据我所见。我不知道TRESTClient
是否使用指定的默认字符集发送REST请求,但查看其来源,我认为没有,但我没有尝试过。
至少,您需要修复EncodeAsUTF8()
功能。它不会产生一个UnicodeString
来保存UTF-8编码的八位字节,就像你认为的那样。它生成UTF-8编码AnsiString
,然后使用RTL的默认Ansi代码页将其转换为UTF-16编码UniodeString
,因此您正在调用丢失UTF-8数据的数据转换。试试这个:
function TTwitterApi.EncodeAsUTF8(UnicodeStr: string): string;
var
UTF8Str: UTF8String;
I: Integer;
begin
UTF8Str := UTF8String(UnicodeStr);
SetLength(Result, Length(UTF8Str));
for I := 1 to Length(UTF8Str) do
Result[I] := Char(Ord(UTF8Str[I]));
end;
这应该允许TRESTClient
至少在其POST数据中对正确的UTF-8数据进行url编码。但是您仍然需要处理charset
请求标头中缺少Content-Type
属性的问题(除非在未指定charset
时Twitter默认为UTF-8。)
现在,尽管如此,如果您发现解决TRESTClient
问题并不适合您,那么我建议改用Indy的TIdHTTP
组件(其中包含更多内容)准确application/x-www-form-urlencoded
实施而不是TRESTClient
正在使用),例如:
procedure TTwitterApi.Send(Tweet: string);
var
Params: TStringList;
begin
Reset;
Params := TStringList.Create;
try
FParams.Add('status=' + Tweet);
FIdHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
FIdHTTP.Request.Charset := 'utf-8';
FIdHTTP.Post('https://api.twitter.com/1.1/statuses/update.json', Params, IndyTextEncoding_UTF8);
finally
Params.Free;
end;
end;
答案 1 :(得分:0)
TRESTRequest不适用于android,它会导致许多问题,特别是UTF8,我无法解决,IdHttp Indy确实可以正常工作。
答案 2 :(得分:0)
我已通过以下方式使用其他API提供程序(而非Twitter)解决了此问题:
function EncodeAsUTF8(UnicodeStr: string): AnsiString; // <-- Note the Ansi
var
UTF8Str: UTF8String;
I: Integer;
begin
UTF8Str := UTF8String(UnicodeStr);
SetLength(Result, Length(UTF8Str));
for I := 1 to Length(UTF8Str) do
Result[I] := AnsiChar(Ord(UTF8Str[I])); // <-- Note the Ansi
end;
...
fRESTClient1 := TRESTClient.Create(nil);
fRESTClient1.Accept := 'application/json';
fRESTClient1.AcceptCharset := 'UTF-8';
fRESTClient1.AcceptEncoding := 'identity';
fRESTClient1.ContentType := 'application/x-www-form-urlencoded';
...
rrOrder := TRESTRequest.Create(nil);
rrOrder.Accept := 'application/json';
rrOrder.AcceptCharset := 'UTF-8';
rrOrder.Client := fRESTClient1; {}
rrOrder.Method := rmPOST;
rrOrder.Resource := 'xxxxxx';
rrOrder.Params.AddItem('', EncodeAsUTF8(aJson), pkREQUESTBODY, [poDoNotEncode]);
rrOrder.Execute;