2009-12-01 56 views
13

Tôi đang cố gắng thực hiện Yêu cầu HTTP từ Delphi bằng cách sử dụng các chức năng WinInet.Cách gửi Yêu cầu POST HTTP trong Delphi bằng cách sử dụng WinInet api

Cho đến nay tôi có:

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; 

Nhưng điều này không làm bất cứ điều gì (Tôi sniffing giao thông http mạng để xem nếu nó hoạt động). Tôi đã sử dụng thành công InternetOpenURL nhưng tôi cũng cần gửi yêu cầu POST và chức năng đó không thực hiện điều đó.

Ai đó có thể chỉ cho tôi một ví dụ đơn giản? Kết quả tôi muốn là để có được trang phản hồi http trong một var như chuỗi.

Trả lời

9

Tôi nhận được tất cả phần url/tên tập tin sai với mã trước đó. Tôi đang sử dụng from Jeff DeVore này ngay bây giờ và nó làm việc tốt:

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 là một chức năng để tách một URL trong "hostname/filename" và TStringArray là một mảng các chuỗi. Tôi vẫn phải xem lại mã ngày mai nhưng có vẻ ổn và trong trình thám thính của tôi, tôi thấy dữ liệu bài đăng và tiêu đề được gửi.

+3

Tôi tìm thấy nguồn mã của bạn cho bạn để bạn có thể trích dẫn tác giả gốc. Tôi đã thay đổi mã để loại bỏ các câu lệnh trường hợp Boolean không được hình thành, và tôi đã thay đổi liên kết giới thiệu để nó không nói dối và tuyên bố là Firefox 3.0.10. –

+1

Tôi không thể tìm thấy đơn vị nào chứa ParseURL hoặc có thể là một thường trình tùy chỉnh của nó. Mã tại: http://delphi.pastebin.com/f1ea3a752 hơi khác và doen't sử dụng ParseURL. – lkessler

+0

Bạn sẽ thêm giá trị tiêu đề tùy chỉnh vào yêu cầu bài đăng như thế nào? – hikari

1

Tham số thứ ba (lpszObjectName) đến HttpOpenRequest phải là URL bạn muốn yêu cầu. Đó là lý do tại sao tài liệu mô tả tham số thứ năm (lpszReferer) là "một con trỏ tới một chuỗi đã kết thúc bằng null xác định URL của tài liệu mà từ đó URL trong yêu cầu (lpszObjectName) đã được lấy."

Dữ liệu đã đăng sẽ được gửi với HttpSendRequest; tham số lpOptional được mô tả như sau:

Con trỏ tới bộ đệm chứa bất kỳ dữ liệu tùy chọn nào sẽ được gửi ngay sau tiêu đề yêu cầu. Thông số này thường được sử dụng cho các hoạt động POST và PUT. Dữ liệu tùy chọn có thể là tài nguyên hoặc thông tin được đăng lên máy chủ. Tham số này có thể là NULL nếu không có dữ liệu tùy chọn để gửi.

Tham số thứ hai là InternetOpen phải là chỉ tên máy chủ; nó không nên bao gồm giao thức. Giao thức mà bạn chỉ định với thông số thứ sáu.

Sau khi bạn gửi yêu cầu, bạn có thể đọc câu trả lời với InternetReadFileInternetQueryDataAvailable.

Không chỉ kiểm tra xem các hàm API có trả lại không và sau đó tiếp tục trên dòng tiếp theo. Nếu họ thất bại, hãy gọi số GetLastError để tìm hiểu lý do. Mã bạn đã đăng sẽ không tăng ngoại lệ, vì vậy thật vô ích khi bắt được bất kỳ mã nào. (Và thật ngu ngốc khi "xử lý" chúng theo cách bạn đang làm như vậy. Đừng bắt một ngoại lệ mà bạn chưa biết cách sửa chữa. Hãy để mọi thứ khác đi đến người gọi, hoặc người gọi của người gọi, v.v. .)

2

Cá nhân tôi thích sử dụng thư viện synapse cho tất cả công việc TCP/IP của tôi. Ví dụ: một bài đăng HTTP đơn giản có thể được mã hóa là:

uses 
    httpsend; 

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

Thư viện được viết và sửa đổi rất dễ dàng cho phù hợp với yêu cầu cụ thể của bạn. Phiên bản lật đổ mới nhất hoạt động mà không có bất kỳ vấn đề nào cho cả Delphi 2009 và Delphi 2010. Khung này không dựa trên thành phần, mà là một loạt các lớp và thủ tục tốt trong môi trường đa luồng.

Các vấn đề liên quan