(粤版/香港文字)
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("CIBS",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0);
// Checking the Internet session handle
if (NULL != hSession)

{
// Connect to the specified server (IP)
hConnection = InternetConnect(hSession,
CibsInfo.Server,
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",
CibsInfo.WebApp,
"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.LastModified);
HttpQueryInfo(hOpenRequest, HTTP_QUERY_LAST_MODIFIED, &HttpInfo.LastModified, &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;
}