在Delphi上使用Wininet API进行HTTP POST

时间:2015-10-30 16:55:31

标签: java json delphi http wininet

我正在使用Delphi 2010向Java应用程序发送HTTP请求。具体来说,我正在发送一个JSON对象。但是,在发送请求时,我不知道发生了什么,但对象不正确。

我发送这样的对象:

    let spacer = UIBarButtonItem(barButtonSystemItem: .FixedSpace, target: nil, action: nil)
    let editButton = UIBarButtonItem(barButtonSystemItem: .Edit, target: self, action: "toggleEditing")
    spacer.width = 6.0

    var leftItems = [UIBarButtonItem]()
    leftItems.append(spacer)
    leftItems.append(editButton)
    navigationItem.setLeftBarButtonItems(leftItems, animated: false)

我的嗅探器读取这样的对象:

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

因此,我的Java应用程序不会读取该对象,而是导致空指针异常。

我的代码在这里:

%�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�

2 个答案:

答案 0 :(得分:2)

JSON默认使用UTF-8,Delphi(2009及更新版本)使用UTF-16作为默认编码。您的代码需要在将JSON传递给HTTPSendRequest之前将其转换为UTF-8字符串。

我还会添加一个请求标头来指示编码,以便Java端知道它是UTF-8。

答案 1 :(得分: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是Delphi 2010中UnicodeString的别名。您按原样发送该字符串的原始字节,而不是将它们编码为UTF -8,这是JSON的默认字符集。正如mjn所说,你在这方面滥用HttpSendRequest()

此外,您的输入JSON字符串在传递给JSONPostRequest()之前似乎已经过url编码(HTTPSendRequest()不会对原始数据进行url编码)。不要对JSON进行url编码,按原样传递原始JSON。

此外,INTERNET_SERVICE_HTTP不是HTTPOpenRequest()的有效标记。

您没有显示调用JSONPostRequest()的代码,因此我无法向您展示如何修复网址编码问题。但是对于实际的帖子,尝试更多类似的东西:

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;