How to send a HTTP POST Request in Delphi using WinInet api

前端 未结 3 2234
栀梦
栀梦 2020-11-28 09:34

I am trying to make HTTP Requests from Delphi using the WinInet functions.

So far I have:

function request:string;
var
  hNet,hURL,hRequest: HINTERNE         


        
相关标签:
3条回答
  • 2020-11-28 10:00

    Personally I prefer to use the synapse library for all of my TCP/IP work. For example, a simple HTTP post can be coded as:

    uses
      httpsend;
    
    function testpost;
    begin
      stm := tStringstream.create('param=value');
      try
        HttpPostBinary('http://example.com',Stm);
      finally
        stm.free;
      end;
    end;
    

    The library is well written and very easy to modify to suit your specific requirements. The latest subversion release works without any problems for both Delphi 2009 and Delphi 2010. This framework is not component based, but rather is a series of classes and procedures which well in a multi-threaded environment.

    0 讨论(0)
  • 2020-11-28 10:05

    I got all the url/filename part messed up with the previous code. I'm using this from Jeff DeVore now and it's working fine:

    function request(const AUrl, AData: AnsiString; blnSSL: Boolean = True): AnsiString;
    var
      aBuffer     : Array[0..4096] of Char;
      Header      : TStringStream;
      BufStream   : TMemoryStream;
      sMethod     : AnsiString;
      BytesRead   : Cardinal;
      pSession    : HINTERNET;
      pConnection : HINTERNET;
      pRequest    : HINTERNET;
      parsedURL   : TStringArray;
      port        : Integer;
      flags       : DWord;
    begin
      ParsedUrl := ParseUrl(AUrl);
    
      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 := INTERNET_DEFAULT_HTTP_PORT;
        pConnection := InternetConnect(pSession, PChar(ParsedUrl[0]), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
    
        if Assigned(pConnection) then
        try
          if (AData = '') then
            sMethod := 'GET'
          else
            sMethod := 'POST';
    
          if blnSSL then
            flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION
          else
            flags := INTERNET_SERVICE_HTTP;
    
          pRequest := HTTPOpenRequest(pConnection, PChar(sMethod), PChar(ParsedUrl[1]), nil, nil, nil, flags, 0);
    
          if Assigned(pRequest) then
          try
            Header := TStringStream.Create('');
            try
              with Header do
              begin
                WriteString('Host: ' + ParsedUrl[0] + sLineBreak);
                WriteString('User-Agent: Custom program 1.0'+SLineBreak);
                WriteString('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+SLineBreak);
                WriteString('Accept-Language: en-us,en;q=0.5' + SLineBreak);
                WriteString('Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'+SLineBreak);
                WriteString('Keep-Alive: 300'+ SLineBreak);
                WriteString('Connection: keep-alive'+ SlineBreak+SLineBreak);
              end;
    
              HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);
    
              if HTTPSendRequest(pRequest, nil, 0, Pointer(AData), Length(AData)) 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 := PChar(BufStream.Memory);
                finally
                  BufStream.Free;
                end;
              end;
            finally
              Header.Free;
            end;
          finally
            InternetCloseHandle(pRequest);
          end;
        finally
          InternetCloseHandle(pConnection);
        end;
      finally
        InternetCloseHandle(pSession);
      end;
    end;
    

    ParseUrl is a function that splits a URL in "hostname / filename" and TStringArray is an array of strings. I still have to review the code tomorrow but it looks fine and in my sniffer I saw the post data and headers being sent.

    0 讨论(0)
  • 2020-11-28 10:17

    The third parameter (lpszObjectName) to HttpOpenRequest should be the URL you wish to request. That's why the documentation describes the fifth parameter (lpszReferer) as "a pointer to a null-terminated string that specifies the URL of the document from which the URL in the request (lpszObjectName) was obtained."

    The posted data gets sent with HttpSendRequest; the lpOptional parameter is described like this:

    Pointer to a buffer containing any optional data to be sent immediately after the request headers. This parameter is generally used for POST and PUT operations. The optional data can be the resource or information being posted to the server. This parameter can be NULL if there is no optional data to send.

    The second parameter to InternetOpen should be just the server name; it should not include the protocol. The protocol you specify with the sixth parameter.

    After you've sent the request, you can read the response with InternetReadFile and InternetQueryDataAvailable.

    Don't just check whether the API functions return zero and then proceed on the next line. If they fail, call GetLastError to find out why. The code you've posted will not raise exceptions, so it's futile to catch any. (And it's foolish to "handle" them the way you're doing so anyway. Don't catch an exception that you don't already know how to fix. Let everything else go up to the caller, or the caller's caller, etc.)

    0 讨论(0)
提交回复
热议问题