2013-11-20 53 views
4

我想用Delphi XE5中的新TRest組件發送推文。我正在尋找一種方法來UTF8編碼我的鳴叫,其中包含IS0-8859-1字符。下面的代碼工作,但涉及代碼頁轉換等是一個更好的方法?任何人?支持TRestClient中的UTF-8編碼字符串Delphi XE5

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; 

回答

5

Twitter的1.1/statuses/update.json URL預計數據在application/x-www-form-urlencoded格式編碼的,所以你需要將TRESTClient.ContentType屬性設置爲ctAPPLICATION_X_WWW_FORM_URLENCODED(它被默認設置爲ctNone)。

至於UTF-8,TRESTClient使用印在內部,和印地支持編碼使用用戶指定的字符集的出站數據,但它不會出現Embarcadero的添加該功能到其TRESTClient界面(它處理在響應中的字符集,但)。我不知道爲什麼英巴卡迪諾會忽略這樣一個重要的功能。僅僅將字符串數據編碼爲UTF-8是不夠的(順便說一句,你沒有正確地做,BTW),但是你也必須告訴Twitter數據已經被UTF-8編碼(通過Content-Type REST的charset屬性頭部),並且TRESTClient不允許你這樣做,據我所知。我不知道TRESTClient是否使用指定的默認字符集發送REST請求,但看看它的來源,我不認爲它確實如此,但我沒有嘗試過。

至少,您需要修復您的EncodeAsUTF8()函數。它不會產生一個包含UTF-8編碼八位字節的UnicodeString,就像您認爲的那樣。它生成一個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到URL編碼,在POST數據正確的UTF-8的數據,至少。但是您仍然必須處理Content-Type請求標頭中缺失的charset屬性的問題(除非在默認情況下,在默認情況下,默認爲UTF-8,否則指定charset)。

現在,所有這一切說,如果你發現周圍的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; 
+0

每個編碼字符的UTF8現在的作品。謝謝! – user3012503

+0

我已經看過REST.Client模塊中的ContentType。使用POST時,ContentType將從請求參數中獲取。 (Se line 2569:LContentType:= ContentType;)如果contenttype是ctNone,它實際上結束爲APPLICATION_X_WWW_FORM_URLENCODED。所以ContentType是正確的。 – user3012503

+0

正如你所說,沒有辦法將UTF-8設置爲charset,但是由於Twitter只接受UTF-8,所以這個方法可行。 – user3012503

0

TRestRequest不支持Android,它會導致許多問題,特別是與UTF8,我解決不了,IdHttp印地做工作正常。

0

我已經解決了這個問題,在下面的方式不同的API提供商(不推特):

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;