HTTP POST其實可以講喺互聨網溝通程序。。。又用户(client)游览器呈報數据到伺服器(server)喥(例如jsp,asp,php以及其它scripting 語言)處,然後輸出某些预設嘅答案。詳细解釋請閱讀rfc2616.pdf文件;此文件非常容易喺互聨網喥搜索得到,尤其喺W3C官方網站。
一般我哋都喺將個HTTP POST運用喺asp-asp,jsp-jsp或asp-jsp網頁溝通程式上。。。啱冇。。。 你有冇想過引用此方案于一般桌面(Desktop)程式上?例如 VB6或VC++咁?
举個例子;如果一個Win32 application需要一個用户驗証登入界面,但問題喺往往喺大機構里面只得總機(伺服器)嘅數据庫先會存有用户嘅資料同登入密碼。
一般人會答:“直接联系嗰數据庫及讀取應要嘅資料咪得囖。。。何必搞到咁腹雜咁麻煩吖。”
啱,如果個方案喺限于一間機構里運作;但萬一喺運作于多間機構于唔同地點呢?喺咁做嘅話,你有冇念過安全嘅問題呢?
也許亦有人答:“通常大機構都有VPN嗎~”
啱,但就一定波及多方面嘅人力資源先能達到预期效果囖。。。
跟住就會有人補充:“不如用WebServices啦!”
答得好;而我想講嘅就喺如何去應用HTTP POST嚟做一個用户登入驗証功能但又唔要用WebServices技術(如下圖)。

呢個方案喺利用Wininet.dll嘅互聨網API函式;而我只需一下幾個API就能達到用户登入驗証功能嘞。
InternetOpen
InternetConnect
HttpOpenRequest
HttpAddRequestHeaders
HttpSendRequest
HttpQueryInfo
InternetQueryDataAvailable
InternetReadFile
InternetCloseHandle
如要知以一上每一個API函式嘅詳细解釋,請参閱MSDN Library為凖。
此實驗分咗两個部分:
1. ASP script用于驗証呈報數据。
2. Win32 VC++程式,用于呈報數据(HTTP POST)到伺服器.
因為個ASP script喺非常简單甚至一睇就明嗰只,所以我亦唔會多解釋。
<
%@ Language
=
VBScript CODEPAGE
=
65001
%
>
<
%
dim
userid
dim
password
dim
result
'
// GET THE CURRENT POSTED DATA
userid
=
request.form(
"
userid
"
)
password
=
request.form(
"
password
"
)
'
// VERIFY THE USERID & PASSWORD
if
strcomp
(userid,
"
admin
"
,
0
)
<>
0
then
result
=
"
Invalid user id!"
elseif
strcomp
(password,
"
p@ssw0rd
"
,
0
)
<>
0
then
result
=
"
Invalid password!"
else
result
=
"
logon successful!"
end
if
'
// WRITE THE RESULT
Response.Write result
'
// STOP ALL RESPONSE
Response.
End
%
>
至于個VC++源代碼就要慝别强調三項:
其一:InternetConnect嘅第二引數就喺個伺服器端IP或多或少URL;當你用此源代碼时就要加倍小心。切記必定要改(如果你嘅伺服器唔喺安装于同開發平台同一部電脑,127.0.0.1也就喺代表localhost)。
其二:HttpOpenRequest嘅第三引數就喺個驗証呈報數据asp script網址。此項也要小心;當你個logon.asp唔係喺eval嘅virtual directory喥;咁就將次换去你設定嘅path嘞。
其三:HttpSendRequest嘅第四引數就喺你所POST嘅資料;亦即喺userid同password。此一定要同asp script里面所冩同一宣告名稱。一旦代諕出錯。。。咁個呈報數据就無法收到嘞。仲有,個POST資料一定要跟以下格式。
useridadmin&password=p@ssw0rd
userid同password喺宣告名稱,而admin同p@ssw0rd就喺個宣告名稱值數。由第二個宣告名稱就要加一個&符諕嚟分開每一個宣告名稱同前一個宣告名稱嘅值數。
當個asp script程式操作完後就會轉回值數;而個Win32 VC++程式就會分析個轉回值數而斷定登入驗証成功或失敗嘞。
實驗源代碼下載: /Files/hackzai/source/vc//httppost_code.zip
long
PostToRemoteServer (LPBYTE pMessage, LPHTTPINFO lphi, LPBYTE pOutput,
int
nMaxBuffer)
{
HTTPINFO HttpInfo
=
{NULL};
LPBYTE lpData
=
NULL;
DWORD dwSize
=
0
;
DWORD dwRet
=
0
;
DWORD dwByteRead
=
0
;
DWORD dwContentLen
=
0
;
DWORD dwByteAvailable
=
0
;
HINTERNET hSession
=
NULL;
HINTERNET hConnection
=
NULL;
HINTERNET hOpenRequest
=
NULL;
char
szHeader[]
=
"
Content-Type: application/x-www-form-urlencoded/r/n
"
;
long
lResult
=
0
;
__try
{
//
Ensure the pass in arguement is valid
if
(NULL
==
lphi) {
return
-
9
;}
if
(NULL
==
pOutput) {
return
-
8
;}
if
(
0
==
nMaxBuffer) {
return
-
7
;}
//
Open a new instance of the Internet Access
hSession
=
InternetOpen(
"
HACKZAI
"
,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0
);
//
Checking the Internet session handle
if
(NULL
!=
hSession)
{
//
Connect to the specified server (IP)
hConnection
=
InternetConnect(hSession,
"
127.0.0.1
"
,
INTERNET_DEFAULT_HTTP_PORT,
NULL,
"
HTTP/1.1
"
,
INTERNET_SERVICE_HTTP,
0
,
0
);
//
Check the Internet connect handle value
if
(NULL
!=
hConnection)
{
//
Open a request to the current server
hOpenRequest
=
HttpOpenRequest(hConnection,
"
POST
"
,
"
/eval/logon.asp
"
,
"
HTTP/1.1
"
,
NULL,
0
,
INTERNET_FLAG_RELOAD,
0
);
//
Check the OpenRequest handle value
if
(NULL
!=
hOpenRequest)
{
//
Add the following header type
//
Content-Type: application/x-www-form-urlencoded
if
(TRUE
==
HttpAddRequestHeaders (hOpenRequest,
szHeader,
strlen(szHeader),
HTTP_ADDREQ_FLAG_REPLACE
|
HTTP_ADDREQ_FLAG_ADD))
{
//
Post the message to server via "POST" method
if
(TRUE
==
HttpSendRequest (hOpenRequest,
NULL,
0
,
(LPSTR)pMessage,
strlen((LPSTR)pMessage)))
{
//
Get all the HTTP information
dwSize
=
sizeof(HttpInfo.ContentType);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_CONTENT_TYPE,
&
HttpInfo.ContentType,
&
dwSize,
0
);
dwSize
=
sizeof(HttpInfo.ContentLength);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_CONTENT_LENGTH,
&
HttpInfo.ContentLength,
&
dwSize,
0
);
dwSize
=
sizeof(HttpInfo.QueryDate);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_DATE,
&
HttpInfo.QueryDate,
&
dwSize,
0
);
dwSize
=
sizeof(HttpInfo.Server);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_SERVER,
&
HttpInfo.Server,
&
dwSize,
0
);
dwSize
=
sizeof(HttpInfo.StatusCode);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_STATUS_CODE,
&
HttpInfo.StatusCode,
&
dwSize,
0
);
dwSize
=
sizeof(HttpInfo.StatusText);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_STATUS_TEXT,
&
HttpInfo.StatusText,
&
dwSize,
0
);
//
Copy the current data into the output buffer
CopyMemory(lphi,
&
HttpInfo, sizeof(HTTPINFO));
//
Reset local variable
dwContentLen
=
0
;
//
Reset pass in output buffer
memset(pOutput, NULL, nMaxBuffer);
//
Continue Query the available data till the EOF
//
Where the InternetQueryDataAvailable return FALSE
while
(InternetQueryDataAvailable(hOpenRequest,
&
dwByteAvailable,
0
,
0
))
{
//
Check the current data available download size
if
(dwByteAvailable
>
0
)
{
//
Accumulate the data length
dwContentLen
+=
dwByteAvailable;
//
Allocate Memory
lpData
=
(LPBYTE)LocalAlloc(LPTR, dwByteAvailable
+
1
);
//
Read File
dwRet
=
InternetReadFile(hOpenRequest, lpData, dwByteAvailable,
&
dwByteRead);
//
Check current downloaded data agaist pass in buffer size
if
(((
long
)strlen((LPSTR)pOutput)
+
(
long
)dwByteAvailable)
<
nMaxBuffer)
{
//
Append the current data into the pass in output buffer
strncat((LPSTR)pOutput, (LPSTR)lpData, dwByteAvailable);
}
//
Release the allocate memory
if
(NULL
!=
lpData) {LocalFree((LPBYTE)lpData);}
lpData
=
NULL;
}
else
{
//
Set Return Value
lResult
=
(
long
)dwContentLen;
//
Exit the current While
Wend
loop
break
;
}
}
}
else
//
Set Return Value
lResult
=
-
6
;
}
else
//
Set Return Value
lResult
=
-
5
;
}
else
//
Set Return Value
lResult
=
-
4
;
}
else
//
Set Return Value
lResult
=
-
3
;
}
else
//
Set Return Value
lResult
=
-
2
;
//
Jump top CleanExit section
goto CleanExit;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
//
PUT YOUR ERROR HANDLE CODE HERE
//
Set the return value
lResult
=
-
1
;
}
CleanExit:
//
Close all the used handle
if
(NULL
!=
hOpenRequest) {InternetCloseHandle(hOpenRequest);}
if
(NULL
!=
hConnection) {InternetCloseHandle(hConnection);}
if
(NULL
!=
hSession) {InternetCloseHandle(hSession);}
//
Set default return value
return
lResult;
}