How to send a HTTP Post Request in Delphi 2010 usi

2019-01-08 00:33发布

问题:

This question already has an answer here:

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

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);

回答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.



回答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;


回答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.