Http訪問有兩種方式,GET和POST,就編程來說GET方式相對簡單點,它不用向服務器提交數據,程序中使用POST方式,
提交數據並從服務器獲取返回值。
爲實現Http訪問,微軟提供了二套API:WinINet, WinHTTP。WinHTTP比WinINet更加安全和健壯,可以這麼認爲WinHTTP是WinINet的升級版本。
程序中,通過一個宏的設置來決定是使用WinHttp還是WinINet。
#define USE_WINHTTP //Comment this line to user wininet.
下面來說說實現Http訪問的流程(兩套API都一樣的流程):
1, 首先我們打開一個Session獲得一個HINTERNET session句柄;
2, 然後我們使用這個session句柄與服務器連接得到一個HINTERNET connect句柄;
3, 然後我們使用這個connect句柄來打開Http 請求得到一個HINTERNET request句柄;
4, 這時我們就可以使用這個request句柄來發送數據與讀取從服務器返回的數據;
5, 最後依次關閉request,connect,session句柄。
- /***********************定義HTTP發送所用方法***********************************/
- HINTERNET OpenSession(LPCWSTR userAgent = 0)
- {
- #ifdef USE_WINHTTP
- return WinHttpOpen(userAgent, NULL, NULL, NULL, NULL);;
- #else
- return InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
- #endif
- }
- HINTERNET Connect(HINTERNET hSession, LPCWSTR serverAddr, int portNo)
- {
- #ifdef USE_WINHTTP
- return WinHttpConnect(hSession, serverAddr, (INTERNET_PORT) portNo, 0);
- #else
- return InternetConnect(hSession, serverAddr, portNo, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
- #endif
- }
- HINTERNET OpenRequest(HINTERNET hConnect, LPCWSTR verb, LPCWSTR objectName, int scheme)
- {
- DWORD flags = 0;
- #ifdef USE_WINHTTP
- if (scheme == INTERNET_SCHEME_HTTPS) {
- flags |= WINHTTP_FLAG_SECURE;
- }
- return WinHttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags);
- #else
- if (scheme == INTERNET_SCHEME_HTTPS) {
- flags |= INTERNET_FLAG_SECURE;
- }
- return HttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags, 0);
- #endif
- }
- BOOL AddRequestHeaders(HINTERNET hRequest, LPCWSTR header)
- {
- SIZE_T len = lstrlenW(header);
- #ifdef USE_WINHTTP
- return WinHttpAddRequestHeaders(hRequest, header, DWORD(len), WINHTTP_ADDREQ_FLAG_ADD);
- #else
- return HttpAddRequestHeaders(hRequest, header, DWORD(len), HTTP_ADDREQ_FLAG_ADD);
- #endif
- }
- BOOL SendRequest(HINTERNET hRequest, const void* body, DWORD size)
- {
- #ifdef USE_WINHTTP
- return WinHttpSendRequest(hRequest, 0, 0, const_cast<void*>(body), size, size, 0);
- #else
- return HttpSendRequest(hRequest, 0, 0, const_cast<void*>(body), size);
- #endif
- }
- BOOL EndRequest(HINTERNET hRequest)
- {
- #ifdef USE_WINHTTP
- return WinHttpReceiveResponse(hRequest, 0);
- #else
- // if you use HttpSendRequestEx to send request then use HttpEndRequest in here!
- return TRUE;
- #endif
- }
- BOOL QueryInfo(HINTERNET hRequest, int queryId, char* szBuf, DWORD* pdwSize)
- {
- #ifdef USE_WINHTTP
- return WinHttpQueryHeaders(hRequest, (DWORD) queryId, 0, szBuf, pdwSize, 0);
- #else
- return HttpQueryInfo(hRequest, queryId, szBuf, pdwSize, 0);
- #endif
- }
- BOOL ReadData(HINTERNET hRequest, void* buffer, DWORD length, DWORD* cbRead)
- {
- #ifdef USE_WINHTTP
- return WinHttpReadData(hRequest, buffer, length, cbRead);
- #else
- return InternetReadFile(hRequest, buffer, length, cbRead);
- #endif
- }
- void CloseInternetHandle(HINTERNET hInternet)
- {
- if (hInternet)
- {
- #ifdef USE_WINHTTP
- WinHttpCloseHandle(hInternet);
- #else
- InternetCloseHandle(hInternet);
- #endif
- }
- }
- /**********************************************************/
- ///通過Http方式發送短信
- string SendSMS_HTTP(const long ececcid,const string & password ,const string & msisdn, const string &smsContent)
- {
- string rtnStr ="-1";
- HINTERNET hSession = 0;
- HINTERNET hConnect = 0;
- HINTERNET hRequest = 0;
- wstring strHeader(L"Content-type: application/x-www-form-urlencoded\r\n");
- // Test data
- CrackedUrl crackedUrl(L"http://pi.f3.cn/SendSMS.aspx");
- string StrPostData = "ececcid=600000&password="+password+"&msisdn="+msisdn+"&smscontent="+smsContent+"&msgtype=5&longcode=";
- StrPostData = string_To_UTF8(StrPostData);
- // Open session.
- hSession = OpenSession(L"HttpPost by [email protected]");
- if (hSession == NULL) {
- cout<<"Error:Open session!\n";
- return "-1";
- }
- // Connect.
- hConnect = Connect(hSession, crackedUrl.GetHostName(), crackedUrl.GetPort());
- if (hConnect == NULL) {
- cout<<"Error:Connect failed!\n";
- return "-1";
- }
- // Open request.
- hRequest = OpenRequest(hConnect, L"POST", crackedUrl.GetPath(), crackedUrl.GetScheme());
- if (hRequest == NULL) {
- cout<<"Error:OpenRequest failed!\n";
- return "-1";
- }
- // Add request header.
- if (!AddRequestHeaders(hRequest, strHeader.c_str())) {
- cout<<"Error:AddRequestHeaders failed!\n";
- return "-1";
- }
- // Send post data.
- if (!SendRequest(hRequest, StrPostData.c_str(), StrPostData.length())) {
- cout<<"Error:SendRequest failed!\n";
- return "-1";
- }
- // End request
- if (!EndRequest(hRequest)) {
- cout<<"Error:EndRequest failed!\n";
- return "-1";
- }
- char szBuf[BUF_SIZE];
- DWORD dwSize = 0;
- szBuf[0] = 0;
- // Query header info.
- #ifdef USE_WINHTTP
- int contextLengthId = WINHTTP_QUERY_CONTENT_LENGTH;
- int statusCodeId = WINHTTP_QUERY_STATUS_CODE;
- int statusTextId = WINHTTP_QUERY_STATUS_TEXT;
- #else
- int contextLengthId = HTTP_QUERY_CONTENT_LENGTH;
- int statusCodeId = HTTP_QUERY_STATUS_CODE;
- int statusTextId = HTTP_QUERY_STATUS_TEXT;
- #endif
- dwSize = BUF_SIZE;
- if (QueryInfo(hRequest, contextLengthId, szBuf, &dwSize)) {
- szBuf[dwSize] = 0;
- cout<<"Content length: "<<szBuf<<endl;
- }
- dwSize = BUF_SIZE;
- if (QueryInfo(hRequest, statusCodeId, szBuf, &dwSize)) {
- szBuf[dwSize] = 0;
- cout<<"Status code: "<< szBuf<<endl;
- }
- dwSize = BUF_SIZE;
- if (QueryInfo(hRequest, statusTextId, szBuf, &dwSize)) {
- szBuf[dwSize] = 0;
- cout<<"Status text:"<<szBuf<<endl;
- }
- // read data.
- for (;;) {
- dwSize = BUF_SIZE;
- if (ReadData(hRequest, szBuf, dwSize, &dwSize) == FALSE) {
- break;
- }
- if (dwSize <= 0) {
- break;
- }
- szBuf[dwSize] = 0;
- rtnStr =::UTF8_To_string(string(szBuf));
- cout<<rtnStr<<endl;//Output 返回值
- }
- CloseInternetHandle(hRequest);
- CloseInternetHandle(hConnect);
- CloseInternetHandle(hSession);
- return rtnStr;
- }
- 以上方法中用到的CrackURL方法在以下CrackURL.h文件中:
- #pragma once
- //#include<iostream>
- //using namespace std;
- #define USE_WINHTTP //Comment this line to user wininet.
- #ifdef USE_WINHTTP
- #include <winhttp.h>
- #pragma comment(lib, "winhttp.lib")
- #else
- #include <wininet.h>
- #pragma comment(lib, "wininet.lib")
- #endif
- // CrackedUrl
- class CrackedUrl {
- int m_scheme;
- wstring m_host;
- int m_port;
- wstring m_path;
- public:
- CrackedUrl(LPCWSTR url)
- {
- URL_COMPONENTS uc = { 0};
- uc.dwStructSize = sizeof(uc);
- const DWORD BUF_LEN = 256;
- WCHAR host[BUF_LEN];
- uc.lpszHostName = host;
- uc.dwHostNameLength = BUF_LEN;
- WCHAR path[BUF_LEN];
- uc.lpszUrlPath = path;
- uc.dwUrlPathLength = BUF_LEN;
- WCHAR extra[BUF_LEN];
- uc.lpszExtraInfo = extra;
- uc.dwExtraInfoLength = BUF_LEN;
- #ifdef USE_WINHTTP
- if (!WinHttpCrackUrl(url, 0, ICU_ESCAPE, &uc)) {
- cout<<"Error:WinHttpCrackUrl failed!\n";
- }
- #else
- if (!InternetCrackUrl(url, 0, ICU_ESCAPE, &uc)) {
- printf("Error:InternetCrackUrl failed!\n");
- }
- #endif
- m_scheme = uc.nScheme;
- m_host = host;
- m_port = uc.nPort;
- m_path = path;
- }
- int GetScheme() const
- {
- return m_scheme;
- }
- LPCWSTR GetHostName() const
- {
- return m_host.c_str();
- }
- int GetPort() const
- {
- return m_port;
- }
- LPCWSTR GetPath() const
- {
- return m_path.c_str();
- }
- static string UrlEncode(const char* p)
- {
- if (p == 0) {
- return string();
- }
- string buf;
- for (;;) {
- int ch = (BYTE) (*(p++));
- if (ch == '\0') {
- break;
- }
- if (isalnum(ch) || ch == '_' || ch == '-' || ch == '.') {
- buf += (char)ch;
- }
- else if (ch == ' ') {
- buf += '+';
- }
- else {
- char c[16];
- wsprintfA(c, "%%%02X", ch);
- buf += c;
- }
- }
- return buf;
- }
- };