Comment envoyer une requête HTTP POST dans Delphi à l'aide de WinInet api
Question
J'essaie de faire des requêtes HTTP à partir de Delphi à l'aide des fonctions WinInet.
Jusqu'à présent, j'ai:
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;
Mais cela ne fait rien (je renifle le trafic réseau http pour voir si cela fonctionne). J'ai utilisé InternetOpenURL mais j'ai également besoin d'envoyer une requête POST, mais cette fonction ne le fait pas.
Quelqu'un pourrait-il me montrer un exemple simple? Le résultat souhaité est d’obtenir la page de réponse http dans une chaîne var as.
La solution
J'ai eu toute la partie url / nom de fichier en désordre avec le code précédent. J'utilise cette de Jeff DeVore et tout fonctionne correctement:
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 est une fonction qui divise une URL dans " hostname / filename " et TStringArray est un tableau de chaînes. Il me reste à relire le code demain, mais il a l'air d'aller et, dans mon renifleur, j'ai vu les données et les en-têtes de messages envoyés.
Autres conseils
Personnellement, je préfère utiliser la bibliothèque synapse pour l'ensemble de mes TCP / IP. travail. Par exemple, une publication HTTP simple peut être codée comme suit:
uses
httpsend;
function testpost;
begin
stm := tStringstream.create('param=value');
try
HttpPostBinary('http://example.com',Stm);
finally
stm.free;
end;
end;
La bibliothèque est bien écrite et très facile à modifier pour répondre à vos besoins spécifiques. La dernière version de Subversion fonctionne sans aucun problème pour Delphi 2009 et Delphi 2010. Ce cadre n’est pas basé sur des composants, mais plutôt sur une série de classes et de procédures qui fonctionnent bien dans un environnement multithread.
Le troisième paramètre (lpszObjectName) à HttpOpenRequest
doit être URL que vous souhaitez demander. C'est pourquoi la documentation décrit le cinquième paramètre (lpszReferer) en tant que "pointeur sur une chaîne terminée par un caractère nul" spécifiant l'URL du document à partir duquel l'URL de la requête (lpszObjectName) a été obtenue. "
Les données publiées sont envoyées avec HttpSendRequest
. / a>; le paramètre lpOptional est décrit comme suit:
Pointeur sur une mémoire tampon contenant les données facultatives à envoyer immédiatement après les en-têtes de la demande. Ce paramètre est généralement utilisé pour les opérations POST et PUT. Les données facultatives peuvent être la ressource ou les informations publiées sur le serveur. Ce paramètre peut être NULL s'il n'y a pas de données facultatives à envoyer.
Le deuxième paramètre à InternetOpen
devrait être juste le nom du serveur ; il ne devrait pas inclure le protocole. Le protocole que vous spécifiez avec le sixième paramètre.
Après avoir envoyé la demande, vous pouvez lire la réponse avec < code> InternetReadFile et InternetQueryDataAvailable
.
Ne vous contentez pas de vérifier si les fonctions de l'API renvoient zéro puis passez à la ligne suivante. Si elles échouent, appelez GetLastError
pour savoir pourquoi. Le code que vous avez posté ne soulèvera pas d'exceptions, il est donc inutile d'en prendre aucune. (Et il est insensé de les "manipuler" comme vous le faites quand même. Ne capturez pas une exception que vous ne savez pas déjà comment corriger. Laissez tout le reste aller jusqu'à l'appelant, ou l'appelant, etc.)