2015-10-30 52 views
1

我正在使用Delphi 2010向Java應用程序發送HTTP請求。具體來說,我發送一個JSON對象。但是,在發送請求時,我不知道發生了什麼,但該對象不正確。使用Delphi上的Wininet API進行HTTP POST

我發送的對象是這樣的:

{"entidad":"1","username":"A","password":"1234"} 

我的嗅探器讀取這樣的對象:

%�7�B�%�2�2�e�n�t�i�d�a�d�%�2�2�%�3�A�%�2�2�8�3�0�0�2�3�0�0�0�%�2�2�%�2�C� 

因此,我的Java應用程序不讀取對象,它導致空指針例外。

我的代碼是在這裏:

function TFormMain.JSONPostRequest(Server,Url,jo : String; blnSSL: Boolean): String; 
var 
    aBuffer  : Array[0..4096] of Char; 
    Header  : TStringStream; 
    BufStream : TMemoryStream; 
    BytesRead : Cardinal; 
    pSession : HINTERNET; 
    pConnection : HINTERNET; 
    pRequest : HINTERNET; 
    port  : Integer; 
    flags  : DWord; 
begin 
    Result := ''; 
    pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
    if Assigned(pSession) then 
    try 
    if blnSSL then 
     Port := INTERNET_DEFAULT_HTTPS_PORT 
    else 
     Port := 9000; 
    pConnection := InternetConnect(pSession, PChar(Server), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0); 
    if Assigned(pConnection) then 
    try 
     if blnSSL then 
     flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION 
     else 
     flags := INTERNET_SERVICE_HTTP; 
     pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(Url), nil, nil, nil, flags, 0); 
     if Assigned(pRequest) then 
     try 
     Header := TStringStream.Create(''); 
     try 
      with Header do 
      begin 
      WriteString('Host: ' + Server + ':' + IntToStr(Port) + sLineBreak); 
      end; 
      HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD); 
      if HTTPSendRequest(pRequest, nil, 0, Pointer(jo), Length(jo)) then 
      begin 
      BufStream := TMemoryStream.Create; 
      try 
       while InternetReadFile(pRequest, @aBuffer, SizeOf(aBuffer), BytesRead) do 
       begin 
       if (BytesRead = 0) then Break; 
       BufStream.Write(aBuffer, BytesRead); 
       end; 
       aBuffer[0] := #0; 
       BufStream.Write(aBuffer, 1); 
       Result := WideCharToString(PChar(BufStream.Memory)); 
      finally 
       BufStream.Free; 
      end; 
      end 
      else 
      raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError)); 
     finally 
      Header.Free; 
     end; 
     finally 
     InternetCloseHandle(pRequest); 
     end; 
    finally 
     InternetCloseHandle(pConnection); 
    end; 
    finally 
    InternetCloseHandle(pSession); 
    end; 
end; 

回答

1

我的嗅探器讀取這樣的對象:

%�7�B�%�2�2�e�n�t�i�d�a�d�%�2�2�%�3�A�%�2�2�8�3�0�0�2�3�0�0�0�%�2�2�%�2�C� 

你的JSON數據是在UTF-16編碼,因爲string是在2010年德爾福UnicodeString別名您發送的原始字節而不是將它們編碼爲UTF-8,這是JSON的默認字符集。正如mjn所說,你在這方面濫用HttpSendRequest()

此外,您輸入的JSON字符串似乎在傳遞到JSONPostRequest()HTTPSendRequest()未對網址進行原始數據編碼)之前已經過網址編碼。不要對JSON進行網址編碼,原樣傳遞原始的JSON。

另外,INTERNET_SERVICE_HTTP不是HTTPOpenRequest()的有效標誌。

你沒有顯示調用JSONPostRequest()的代碼,所以我不能告訴你如何解決url編碼問題。但嘗試更像這樣的實際職位:

function WinInetErrorMsg(Err: DWORD): string; 
var 
    ErrMsg: array of Char; 
    ErrLen: DWORD; 
begin 
    if Err = ERROR_INTERNET_EXTENDED_ERROR then 
    begin 
    ErrLen := 0; 
    InternetGetLastResponseInfo(Err, nil, ErrLen); 
    if GetLastError() = ERROR_INSUFFICIENT_BUFFER then 
    begin 
     SetLength(ErMsg, ErrLen); 
     InternetGetLastResponseInfo(Err, PChar(ErMsg), ErrLen); 
     SetString(Result, PChar(ErrMsg), ErrLen); 
    end else begin 
     Result := 'Unknown WinInet error'; 
    end; 
    end else 
    Result := SysErrorMessage(Err); 
end; 

function TFormMain.JSONPostRequest(const Server, Url: string; const jo : UTF8String; blnSSL: Boolean): String; 
var 
    aBuffer  : Array of Byte; 
    Header  : String; 
    BufStream : TStringStream; 
    BytesRead : DWORD; 
    pSession : HINTERNET; 
    pConnection : HINTERNET; 
    pRequest : HINTERNET; 
    port  : Integer; 
    flags  : DWORD; 
begin 
    Result := ''; 
    pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
    if not Assigned(pSession) then 
    raise Exception.Create('InternetOpen failed. ' + WinInetErrorMsg(GetLastError)); 
    try 
    if blnSSL then 
     Port := INTERNET_DEFAULT_HTTPS_PORT 
    else 
     Port := 9000; 
    pConnection := InternetConnect(pSession, PChar(Server), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0); 
    if not Assigned(pConnection) then 
     raise Exception.Create('InternetConnect failed. ' + WinInetErrorMsg(GetLastError)); 
    try 
     if blnSSL then 
     flags := INTERNET_FLAG_SECURE 
     else 
     flags := 0; 
     pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(Url), nil, nil, nil, flags, 0); 
     if not Assigned(pRequest) then 
     raise Exception.Create('HttpOpenRequest failed. ' + WinInetErrorMsg(GetLastError)); 
     try 
     Header := 'Host: ' + Server + ':' + IntToStr(Port) + #13#10 + 
        'Content-Type: application/json; charset=UTF-8'#13#10; 

     if not HttpAddRequestHeaders(pRequest, PChar(Header), Length(Header), HTTP_ADDREQ_FLAG_ADD) then 
      raise Exception.Create('HttpAddRequestHeaders failed. ' + WinInetErrorMsg(GetLastError)); 

     if not HTTPSendRequest(pRequest, nil, 0, PAnsiChar(jo), Length(jo)) then 
      raise Exception.Create('HTTPSendRequest failed. ' + WinInetErrorMsg(GetLastError)); 

     SetLength(aBuffer, 4096); 
     BufStream := TStringStream.Create('', TEncoding.Default); 
     try 
      repeat 
      if not InternetReadFile(pRequest, PByte(aBuffer), Length(aBuffer), BytesRead) then 
       raise Exception.Create('InternetReadFile failed. ' + WinInetErrorMsg(GetLastError)); 
      if (BytesRead = 0) then Break; 
      BufStream.WriteBuffer(PByte(aBuffer)^, BytesRead); 
      until False; 
      Result := BufStream.DataString; 
     finally 
      BufStream.Free; 
     end; 
     finally 
     InternetCloseHandle(pRequest); 
     end; 
    finally 
     InternetCloseHandle(pConnection); 
    end; 
    finally 
    InternetCloseHandle(pSession); 
    end; 
end; 
+0

謝謝,雷米。這段代碼幫助我解決了我的問題。 –

+0

@ FelipeCeballos-Desystec然後,您可以通過點擊此帖子左下方的複選標記來接受答案。 – RepeatUntil

+0

謝謝,@AbdulrahmanAljehani。我已經做到了。 –

2

JSON使用UTF-8默認的Delphi(2009和更新)使用UTF-16作爲默認編碼。在將代碼傳遞給HTTPSendRequest之前,您的代碼需要將JSON轉換爲UTF-8字符串。

我還會添加一個請求頭來表示編碼,以便Java方面知道它是UTF-8。

+0

同意。 'HTTPSendRequest()'的最後一個參數期望**原始字節**,而不是**字符串**。此外,使用WideCharToString(PChar(BufStream.Memory));'是非常可疑的,因爲在D2010中PChar()是'PWideChar',HTTP響應數據通常不被編碼爲UTF-16。 –