使用 WinInet (Windows Internet API) 模擬瀏覽器表單提交 (HTTP POST),關鍵在於正確設定 Content-Type: application/x-www-form-urlencoded 標頭,並對表單數據進行 URL 編碼。本文提供 MFC CInternetSession 封裝版與純 SDK 版雙重實現代碼。
Content-Type: application/x-www-form-urlencoded (必須,否則 IIS ASP/ASP.NET 不會填充 Request.Form 集合)。name=value&name2=value2,空格編碼為 + 或 %20,特殊字元 %+十六進位 (如 & → %26)。CString::UrlEncode (MFC/ATL) 或自寫 URL Encode。bool HttpPostForm(const CString& server, const CString& action, const CString& formData, CString& response) {
CString headers = _T("Content-Type: application/x-www-form-urlencoded");
// formData 範例: "username=admin&password=123456&submit=%E7%99%BB%E5%BD%95"
CInternetSession session(_T("MyApp/1.0"));
CHttpConnection* pConn = NULL;
CHttpFile* pFile = NULL;
try {
pConn = session.GetHttpConnection(server, INTERNET_DEFAULT_HTTP_PORT);
pFile = pConn->OpenRequest(CHttpConnection::HTTP_VERB_POST, action);
// 發送請求
BOOL ok = pFile->SendRequest(headers, (LPVOID)(LPCTSTR)formData, formData.GetLength());
if (!ok) { delete pFile; delete pConn; return false; }
// 讀取回應
CString line;
response.Empty();
while (pFile->ReadString(line)) response += line + _T("\n");
} catch (CInternetException* e) {
TCHAR err[256]; e->GetErrorMessage(err, 255);
TRACE(_T("WinInet Error: %s\n"), err);
e->Delete();
if (pFile) delete pFile;
if (pConn) delete pConn;
return false;
}
delete pFile;
delete pConn;
return true;
}
// 調用
CString resp;
HttpPostForm(_T("api.example.com"), _T("/login"), _T("user=admin&pass=123"), resp);
bool HttpPostSDK(const char* server, const char* action, const char* formData) {
HINTERNET hSession = InternetOpen("MyApp/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hSession) return false;
HINTERNET hConnect = InternetConnect(hSession, server, INTERNET_DEFAULT_HTTP_PORT,
NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) { InternetCloseHandle(hSession); return false; }
const char* accept = "Accept: */*";
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", action, NULL, NULL, &accept, 0, 0);
if (!hRequest) { InternetCloseHandle(hConnect); InternetCloseHandle(hSession); return false; }
const char* headers = "Content-Type: application/x-www-form-urlencoded";
BOOL ok = HttpSendRequest(hRequest, headers, strlen(headers), (LPVOID)formData, strlen(formData));
// 讀取回應 (略)
char buf[1024]; DWORD read;
while (InternetReadFile(hRequest, buf, sizeof(buf)-1, &read) && read) { buf[read]=0; OutputDebugStringA(buf); }
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
return ok;
}
CString UrlEncode(const CString& src) {
CString dest;
for (int i=0; i
INTERNET_DEFAULT_HTTPS_PORT (443),InternetConnect 第三參數改 443,HttpOpenRequest 加 INTERNET_FLAG_SECURE。HttpSendRequestEx + InternetWriteFile 分塊寫入。InternetGetCookie/SetCookie 或讓 CInternetSession 自動管理。InternetSetOption(INTERNET_OPTION_CONNECT_TIMEOUT/RECEIVE_TIMEOUT)。WinInet 是 Windows 系統級 HTTP 客戶端,無需第三方庫 (如 libcurl),部署極輕量,適合簡單 REST API 呼叫、表單提交、檔案上傳/下載。