Come inviare una richiesta POST HTTP in Delphi usando WinInet api

Sto cercando di fare richieste HTTP da Delphi usando le funzioni WinInet.

Finora ho:

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(hURLnil) then hRequest := HttpOpenRequest(hURL, 'POST', PChar('param=value'),'HTTP/1.0',PChar(''), nil, INTERNET_FLAG_RELOAD or INTERNET_FLAG_PRAGMA_NOCACHE,0); if(hRequestnil) 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; 

Ma questo non fa nulla (sto sniffando il traffico di rete http per vedere se funziona). Ho usato con successo InternetOpenURL ma ho anche bisogno di inviare la richiesta POST e quella funzione non lo fa.

Qualcuno potrebbe mostrarmi un semplice esempio? Il risultato che voglio è ottenere la pagina di risposta http in una var come stringa.

    Ho ottenuto tutta la parte url / filename incasinata del codice precedente. Sto usando questo da Jeff DeVore ora e sta funzionando bene:

     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 è una funzione che divide un URL in “nomehost / nome file” e TStringArray è una matrice di stringhe. Devo ancora rivedere il codice domani ma sembra a posto e nel mio sniffer ho visto i dati e le intestazioni dei messaggi inviati.

    Personalmente preferisco usare la libreria sinapsi per tutto il mio lavoro TCP / IP. Ad esempio, un semplice post HTTP può essere codificato come:

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

    La libreria è ben scritta e molto facile da modificare per soddisfare le vostre esigenze specifiche. L’ultima versione di subversion funziona senza problemi sia per Delphi 2009 che per Delphi 2010. Questo framework non è basato sui componenti, ma piuttosto una serie di classi e procedure che si trovano bene in un ambiente multi-thread.

    Il terzo parametro (lpszObjectName) in HttpOpenRequest dovrebbe essere l’ URL che desideri richiedere. Ecco perché la documentazione descrive il quinto parametro (lpszReferer) come “un puntatore a una stringa terminata da null che specifica l’URL del documento da cui è stato ottenuto l’URL nella richiesta (lpszObjectName).”

    I dati inviati vengono inviati con HttpSendRequest ; il parametro lpOptional è descritto in questo modo:

    Puntatore a un buffer contenente dati facoltativi da inviare immediatamente dopo le intestazioni della richiesta. Questo parametro viene generalmente utilizzato per le operazioni POST e PUT. I dati facoltativi possono essere la risorsa o le informazioni inviate al server. Questo parametro può essere NULL se non ci sono dati opzionali da inviare.

    Il secondo parametro di InternetOpen dovrebbe essere solo il nome del server ; non dovrebbe includere il protocollo. Il protocollo specificato con il sesto parametro.

    Dopo aver inviato la richiesta, è ansible leggere la risposta con InternetReadFile e InternetQueryDataAvailable .

    Non basta controllare se le funzioni API restituiscono zero e quindi procedere alla riga successiva. Se falliscono, chiama GetLastError per scoprire perché. Il codice che hai postato non solleverà eccezioni, quindi è inutile prenderne. (Ed è sciocco “gestirli” nel modo in cui lo fai comunque. Non rilevare un’eccezione che non sai già come risolvere. Lascia che tutto il resto salga al chiamante, al chiamante del chiamante, ecc. .)