Wie eine HTTP-POST-Anfrage in Delphi mit WinInet api senden
Frage
Ich versuche, HTTP-Anfragen von Delphi mit den WinInet-Funktionen zu machen.
Bisher habe ich:
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;
Aber das tut nichts (ich Sniffing Netzwerk HTTP-Verkehr, um zu sehen, ob es funktioniert). Ich habe InternetOpenURL erfolgreich eingesetzt, aber ich brauche auch POST-Anforderung und die Funktion nicht zu senden, die nicht tun.
Könnte jemand zeigen Sie mir ein einfaches Beispiel? Das Ergebnis, das ich will, ist die HTTP-Antwort-Seite in einem var als String zu erhalten.
Lösung
Ich habe alle die URL / Dateiname Teil mit dem vorherigen Code durcheinander. Ich verwende diesen von Jeff DeVore jetzt und es funktioniert gut:
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 ist eine Funktion, die eine URL in „Hostname / Dateiname“ aufspaltet und TStringArray ist ein Array von Strings. Ich habe immer noch den Code morgen überprüfen, aber es sieht gut aus und in meinem Sniffer sah ich die Post-Daten und Header gesendet werden.
Andere Tipps
Persönlich bevorzuge ich die Synapse rel="nofollow Bibliothek für alle meine TCP / IP Arbeit. Zum Beispiel kann eine einfache HTTP-Post kodiert werden:
uses
httpsend;
function testpost;
begin
stm := tStringstream.create('param=value');
try
HttpPostBinary('http://example.com',Stm);
finally
stm.free;
end;
end;
Die Bibliothek ist gut geschrieben und sehr einfach zu ändern, um Ihre spezifische Anforderungen anpassen. Die neueste Subversion Release funktioniert ohne Probleme sowohl für Delphi 2009 und Delphi 2010. Dieser Rahmen nicht Komponente basiert, sondern ist eine Reihe von Klassen und Verfahren, die auch in einer Multi-Threaded-Umgebung.
Der dritte Parameter (lpszObjectName) an HttpOpenRequest
sollte die URL Sie möchten beantragen. Deshalb ist die Dokumentation des fünften Parameter (lpszReferer) beschreibt als „ein Zeiger auf einen nullterminierten String, der die URL des Dokuments angibt, von dem die URL in der Anfrage (lpszObjectName) erhalten.“
Die eingestellten Daten werden mit HttpSendRequest
gesendet; der LpOptional Parameter wird wie folgt beschrieben:
Zeiger auf einen Puffer alle optionalen Daten enthalten, unmittelbar nachdem die Anfrage-Header gesendet werden sollen. Dieser Parameter wird für POST und PUT-Operationen verwendet. Die optionalen Daten können die Ressource oder Informationen werden an den Server gesendet. Dieser Parameter kann NULL sein, wenn es keine optionalen Daten zu senden.
Der zweite Parameter an InternetOpen
sollte nur der Servername ; es sollte nicht das Protokoll enthalten. Das Protokoll, das Sie mit dem sechsten Parameter angeben.
Nachdem Sie die Anfrage gesendet haben, können Sie die Antwort mit InternetReadFile
und InternetQueryDataAvailable
.
Sie nicht nur prüfen, ob die API-Funktionen Null zurück und dann in der nächsten Zeile fort. Wenn sie versagen, nennen GetLastError
um herauszufinden, warum. Der Code, den Sie geschrieben haben, werden Ausnahmen nicht erhöhen, so ist es sinnlos jeder zu fangen. (Und es ist dumm zu „behandeln“, um sie so, wie Sie sind so ohnehin tun. Sie eine Ausnahme nicht fangen, die Sie nicht bereits wissen, wie sie zu beheben. Lassen Sie alles andere an den Anrufer gehen, oder der Anrufer des Anrufers, usw. ).