支持TRestClient Delphi XE5中的UTF-8编码字符串

use*_*503 4 delphi twitter utf-8 delphi-xe5

我想在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;
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 6

Twitter的1.1/statuses/update.jsonURL期望数据以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编码(通过REST头的charset属性Content-Type) ,TRESTClient据我所见,并不允许你这样做.我不知道是否TRESTClient使用指定的默认字符集发送REST请求,但查看其来源,我不认为它,但我没有尝试过.

至少,你需要修复你的EncodeAsUTF8()功能.它不会产生一个UnicodeString包含UTF-8编码的八位字节,就像你认为的那样.它生成UTF-8编码AnsiString,然后UniodeString使用RTL的默认Ansi代码页将其转换为UTF-16编码,因此您正在调用丢失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;
Run Code Online (Sandbox Code Playgroud)

这应该允许TRESTClient至少在其POST数据中对正确的UTF-8数据进行url编码.但是您仍然必须处理请求标头中缺少charset属性的问题Content-Type(除非在charset指定no时Twitter默认为UTF-8 ).

现在,所有这些说,如果你发现解决TRESTClient问题并不适合你,那么我建议改用Indy的TIdHTTP组件(它具有application/x-www-form-urlencodedTRESTClient使用更准确的实现),例如:

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;
Run Code Online (Sandbox Code Playgroud)