كيفية إرسال طلب HTTP POST في دلفي باستخدام WININET API
سؤال
واني اسعى الى تقديم طلبات HTTP من دلفي باستخدام وظائف WININET.
وحتى الآن لدي:
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 في فار كسلسلة.
المحلول
وحصلت على كل جزء عنوان / اسم الملف عابث مع رمز السابقة. أنا باستخدام هذه من جيف 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 هو مجموعة من السلاسل. لا يزال لدي لمراجعة شفرة غدا لكنها تبدو على ما يرام وفي بلدي الشم رأيت بيانات آخر ورؤوس إرسالها.
نصائح أخرى
وشخصيا انا افضل استخدام مكتبة لجميع من بلدي TCP / IP عمل. على سبيل المثال، وظيفة HTTP بسيطة يمكن أن تكون مشفرة على النحو التالي:
uses
httpsend;
function testpost;
begin
stm := tStringstream.create('param=value');
try
HttpPostBinary('http://example.com',Stm);
finally
stm.free;
end;
end;
والمكتبة هي مكتوبة بشكل جيد وسهلة جدا لتعديل لتلائم الاحتياجات المحددة الخاصة بك. الإصدار الأخير التخريب يعمل بدون أي مشاكل لكلا دلفي 2009 و 2010. دلفي هذا الإطار ليس عنصر أساس، وإنما هو عبارة عن سلسلة من الفصول الدراسية والإجراءات التي جيدا في بيئة متعددة الخيوط.
والمعلمة الثالث (lpszObjectName) لوينبغي أن يكون HttpOpenRequest
لل URL م> كنت ترغب في طلب. هذا هو السبب تصف وثائق المعلمة الخامسة (lpszReferer) بأنه "مؤشر إلى سلسلة خالية منتهية يحدد URL من المستند الذي تم الحصول على URL في الطلب (lpszObjectName)."
ويحصل على إرسال البيانات التي تم نشرها مع HttpSendRequest
. يتم وصف المعلمة lpOptional مثل هذا:
ومؤشر لالعازلة التي تحتوي على أية بيانات اختيارية ليتم إرسالها مباشرة بعد رؤوس الطلب. يتم استخدام هذه المعلمة بشكل عام لعمليات ما بعد وPUT. يمكن أن تكون البيانات الاختيارية مورد أو المعلومات التي يتم نشرها إلى الخادم. هذه المعلمة يمكن أن تكون فارغة إذا كان هناك أية بيانات اختيارية لإرسال.
اقتباس فقرة> والمعلمة الثانية إلى InternetOpen
يجب أن يكون <م> فقط اسم الملقم م>. فإنه لا ينبغي أن يشمل البروتوكول. البروتوكول الذي تحدده مع المعلمة السادسة.
وبعد أن كنت قد أرسلت هذا الطلب، يمكنك قراءة الاستجابة مع InternetReadFile
و InternetQueryDataAvailable
.
ولا تحقق فقط ما إذا كانت وظائف API تعود الصفر ومن ثم المضي قدما على السطر التالي. إذا فشلوا، والدعوة GetLastError
لمعرفة السبب. سوف رمز كنت قد نشرت لا تثير الاستثناءات، لذلك فمن غير المجدي للقبض على أي. (وانه من الحماقة أن "التعامل مع" لهم الطريق كنت تفعل ذلك على أي حال. لا يمسك استثناء أن كنت لا تعرف بالفعل كيفية إصلاح. دعونا كل شيء آخر ترتفع إلى المتصل أو المتصل المتصل، الخ .)