簡體   English   中英

在Delphi上使用Wininet API進行HTTP POST

[英]HTTP POST with Wininet API on Delphi

我正在使用Delphi 2010向Java應用程序發送HTTP請求。 具體來說,我正在發送一個JSON對象。 但是,在發送請求時,我不知道發生了什么,但對象不正確。

我像這樣發送對象:

{"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;  

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

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

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

 % 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是Delphi 2010中UnicodeString的別名。您正在發送該字符串的原始字節,而不是將它們編碼為UTF-8,這是JSON的默認字符集。 正如mjn所說,你在這方面濫用HttpSendRequest()

此外,您的輸入JSON字符串似乎在傳遞給JSONPostRequest()之前已經過url編碼( HTTPSendRequest()不會對原始數據進行url編碼)。 不要對JSON進行URL編碼,按原樣傳遞原始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;  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM