2009-12-01 61 views
13

WinInet関数を使用してDelphiからHTTPリクエストを作成しようとしています。WinInet APIを使用してDelphiでHTTP POSTリクエストを送信する方法

これまでのところ私が持っている:

function request:string; 
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://example.com'),INTERNET_DEFAULT_HTTP_PORT,nil,nil,INTERNET_SERVICE_HTTP,0,DWORD(0)); 
    if(hURL<>nil) then 
     hRequest := HttpOpenRequest(hURL, 'POST', PChar('param=value'),'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 
    on E : Exception do 
     ShowMessage(E.ClassName+' error raised, with message : '+E.Message); 
    end; 
    end 
end; 

しかし、これは(私はそれが動作するかどうかを確認するために、ネットワークのHTTPトラフィックを盗聴しています)何もしません。 私はInternetOpenURLを正常に使用しましたが、POSTリクエストを送信する必要があり、その機能はそれを行いません。

誰かが私に簡単な例を表示できますか?私が望む結果は、http応答ページをvarの文字列として取得することです。

答えて

9

URL /ファイル名の部分がすべて前のコードにぶち壊されました。私は今、このfrom Jeff DeVoreを使用していますし、それが正常に働いています:

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を「は、ホスト名/ファイル名」にURLを分割関数であり、TStringArrayは、文字列の配列です。私はまだ明日のコードを見直さなければならないが、それはうまく見えるし、スニファでポストデータとヘッダーが送信されているのを見た。

+3

元の著者を引用できるように、コードのソースが見つかりました。私はコードを変更して誤ったブールケースのステートメントを削除し、リファラーを変更してFirefox 3.0.10であると主張し、主張しません。 –

+1

どのユニットにParseURLが含まれているのか、それともカスタムルーチンが含まれているのかわかりません。 http://delphi.pastebin.com/f1ea3a752のコードは多少異なり、ParseURLを使用しません。 – lkessler

+0

投稿リクエストにカスタムヘッダーの値をどのように追加しますか? – hikari

1

第3パラメータ(lpszObjectName)からHttpOpenRequestは、のURLになります。そのため、ドキュメントでは、5番目のパラメータ(lpszReferer)が「要求のURL(lpszObjectName)が取得されたドキュメントのURLを指定するヌル終了文字列へのポインタ」と記載されています。

投稿されたデータはHttpSendRequestで送信されます。 lpOptionalパラメーターは次のように記述されます。

要求ヘッダーの直後に送信される任意のデータを含むバッファーへのポインター。このパラメータは、POSTおよびPUT操作で一般的に使用されます。オプションのデータは、サーバーに送信されるリソースまたは情報です。送信するオプションのデータがない場合、このパラメータはNULLになります。

InternetOpenの2番目のパラメータはだけで、サーバー名でなければなりません。プロトコルを含んではいけません。 6番目のパラメーターで指定するプロトコル。

リクエストを送信した後、InternetReadFileInternetQueryDataAvailableという応答を読むことができます。

API関数がゼロを返してから次の行に進むかどうかだけではありません。失敗した場合は、GetLastErrorに電話して理由を調べます。投稿したコードは例外を発生させませんので、それを捕まえるのは無駄です。 (とにかくやっているように、それらを「扱う」ことは愚かなことです。あなたは、修正する方法がわからないという例外をキャッチしないでください。それ以外のものはすべて、発信者、または発信者の発信者などに行きましょう。 。)

2

個人的には、すべてのTCP/IP作業にsynapseライブラリを使用することをお勧めします。たとえば、単純なHTTPポストは、次のようにコード化することができます。

uses 
    httpsend; 

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

ライブラリはよく書かれており、特定の要件に合わせて変更するのが非常に簡単です。最新のSubversionリリースは、Delphi 2009とDelphi 2010の両方で問題なく動作します。このフレームワークはコンポーネントベースではなく、マルチスレッド環境に適した一連のクラスとプロシージャです。

関連する問題