How to send a HTTP Post Request in Delphi 2010 using WinInet

12,867

Solution 1

Major problems:

  • The second parameter of InternetConnect should contain only the name of the server, not the entire URL of the server-side script.

  • The third parameter of HttpOpenRequest should be the file name (URL) of the script, not the POST data!

  • The actual POST data should be the forth parameter of HttpSendRequest.

Minor problems

  • INTERNET_OPEN_TYPE_PRECONFIG or INTERNET_OPEN_TYPE_PRECONFIG: It is sufficient with INTERNET_OPEN_TYPE_PRECONFIG.

  • DWORD(0) is overkill. 0 is enough.

Sample Code

I use the following code to POST data:

procedure WebPostData(const UserAgent: string; const Server: string; const Resource: string; const Data: AnsiString); overload;
var
  hInet: HINTERNET;
  hHTTP: HINTERNET;
  hReq: HINTERNET;
const
  accept: packed array[0..1] of LPWSTR = (PChar('*/*'), nil);
  header: string = 'Content-Type: application/x-www-form-urlencoded';
begin
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hHTTP := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
    try
      hReq := HttpOpenRequest(hHTTP, PChar('POST'), PChar(Resource), nil, nil, @accept, 0, 1);
      try
        if not HttpSendRequest(hReq, PChar(header), length(header), PChar(Data), length(Data)) then
          raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
      finally
        InternetCloseHandle(hReq);
      end;
    finally
      InternetCloseHandle(hHTTP);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

For instance:

WebPostData('My UserAgent', 'www.rejbrand.se', 'mydir/myscript.asp', 'value=5');

Update in response to answer by OP

To read data from the Internet, use InternetReadFile function. I use the following code to read a small (one-line) text file from the Internet:

function WebGetData(const UserAgent: string; const Server: string; const Resource: string): string;
var
  hInet: HINTERNET;
  hURL: HINTERNET;
  Buffer: array[0..1023] of AnsiChar;
  i, BufferLen: cardinal;
begin
  result := '';
  hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    hURL := InternetOpenUrl(hInet, PChar('http://' + Server + Resource), nil, 0, 0, 0);
    try
      repeat
        InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
        if BufferLen = SizeOf(Buffer) then
          result := result + AnsiString(Buffer)
        else if BufferLen > 0 then
          for i := 0 to BufferLen - 1 do
            result := result + Buffer[i];
      until BufferLen = 0;
    finally
      InternetCloseHandle(hURL);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

Sample usage:

WebGetData('My UserAgent', 'www.rejbrand.se', '/MyDir/update/ver.txt')

This function thus only reads data, with no prior POST. However, the InternetReadFile function can also be used with a handle created by HttpOpenRequest, so it will work in your case also. You do know that the WinInet reference is MSDN, right? All Windows API functions are described in detail there, for instance InternetReadFile.

Solution 2

var
  BufferIn : INTERNET_BUFFERS;
  Buffer: array[0..1024] of Byte;
  FTmp: TSomeStream:
  FURL: string;
  ...
begin
... // Create FTmp, set FUrl, ...

  NetHandle := InternetOpen( 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3',
                          INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  UrlHandle := HttpOpenRequest(NetHandle, 'POST', PChar(FURL), nil, nil, nil, INTERNET_FLAG_NO_CACHE_WRITE, 0);

  ... // Check handles, etc
  try
    BufferIn.dwBufferTotal := FTmp.Size;

    if not HttpSendRequestEx(UrlHandle, @BufferIn, nil, 0, 0) then
      raise Exception.CreateFmt('Error on HttpSendRequestEx %d\n', [GetLastError()]);

    size := FTmp.Read(Buffer, 1024);
    InternetWriteFile(UrlHandle, @Buffer, size, BytesWritten);

    while (BytesWritten = size) and (BytesWritten > 0) do
    begin
      size := FTmp.Read(Buffer, 1024);
      InternetWriteFile(UrlHandle, @Buffer, size, BytesWritten);
    end;
  finally
    FTmp.Free;

    InternetCloseHandle(UrlHandle);
    InternetCloseHandle(NetHandle);
  end;

Solution 3

There is a library (called 'HTTPGet component for Delphi 32') on http://www.utilmind.com. It installs a visual control into your component palette. It does exactly what you want, so you may want to take a look.

Share:
12,867
noxwow
Author by

noxwow

Updated on June 11, 2022

Comments

  • noxwow
    noxwow almost 2 years

    I want to send a HTTP Post Request in Delphi 2010 using WinInet, but my script doesn't work ;/

    It's my Delphi script:

    uses WinInet;
    procedure TForm1.Button1Click(Sender: TObject);
    var
      hNet,hURL,hRequest: HINTERNET;
    begin
      hNet := InternetOpen(PChar('User Agent'),INTERNET_OPEN_TYPE_PRECONFIG or INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
      if Assigned(hNet) then
      begin
      try
        hURL := InternetConnect(hNet,PChar('http://localhost/delphitest.php'),INTERNET_DEFAULT_HTTP_PORT,nil,nil,INTERNET_SERVICE_HTTP,0,DWORD(0));
        if(hURL<>nil) then
          hRequest := HttpOpenRequest(hURL, 'POST', PChar('test=test'),'HTTP/1.0',PChar(''), nil, INTERNET_FLAG_RELOAD or INTERNET_FLAG_PRAGMA_NOCACHE,0);
        if(hRequest<>nil) then
          HttpSendRequest(hRequest, nil, 0, nil, 0);
        InternetCloseHandle(hNet);
      except
          ShowMessage('error');
        end
      end;
    end;
    

    and my PHP script:

    $data = $_POST['test'];
    $file = "test.txt";
    $fp = fopen($file, "a");
    flock($fp, 2);
    fwrite($fp, $data);
    flock($fp, 3);
    fclose($fp);