Browse Source

重点问题:使用WinHttpWriteData时,必须在WinHttpSendRequest中指定Data的大小;在Header中好像无效。而且FormData和PostData要使用char做为存储单元,不能使用wchar_t,否则会有异常错误。

JeffWang 3 năm trước cách đây
mục cha
commit
4e2a19a7dd
4 tập tin đã thay đổi với 314 bổ sung432 xóa
  1. 10 114
      WINHTTPS/WINHTTPS/HTTPDef.h
  2. 170 156
      WINHTTPS/WINHTTPS/HTTPHelper.cpp
  3. 10 11
      WINHTTPS/WINHTTPS/HTTPHelper.h
  4. 124 151
      WINHTTPS/WINHTTPS/WINHTTPS.cpp

+ 10 - 114
WINHTTPS/WINHTTPS/HTTPDef.h

@@ -5,12 +5,12 @@
 #endif
 
 #define CRLF L"\r\n"
-#define CONTENT_LENGTH L"Content-Length: "
-#define CONTENT_TYPE L"Content-Type: "
+#define CONTENT_LENGTH L"Content-Length"
+#define CONTENT_TYPE L"Content-Type"
 #define BOUNDARY L"----WebKitFormBoundary7MA4YWxkTrZu0gW"
 #define FORMDATAHEADER L"Content-Type:multipart/form-data;boundary="##BOUNDARY
 #define FORMURLENCODEDDATAHEADER L"Content-Type:application/x-www-form-urlencoded"
-#define FORMDATA_FILE_FORMAT L"------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"%s\"; %s=\"%s\"\r\nContent-Type: %s\r\n"
+#define FORMDATA_FILE_FORMAT "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"%s\"; %s=\"%s\"\r\nContent-Type: %s\r\n"
 /*
 e.g.
 ------WebKitFormBoundary7MA4YWxkTrZu0gW
@@ -20,7 +20,7 @@ Content-Type:image/gif
 
 */
 
-#define FORMDATA_TEXT_FORMAT L"------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"%s\";\r\n\r\n%s=\"%s\"\r\n"
+#define FORMDATA_TEXT_FORMAT "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"%s\";\r\n\r\n%s=\"%s\"\r\n"
 /*
 e.g.
 ------WebKitFormBoundary7MA4YWxkTrZu0gW
@@ -59,76 +59,9 @@ typedef enum{
 typedef struct HTTPItem
 {
 #if _MSVC_LANG >= 201402L // C++14
-	std::string url;
-	std::string host;
-	std::string Method = "GET";
-	// 请求超时时间;
-	DWORD	Timeout=10000;
-	// 读写超时时间;
-	DWORD ReadWriteTimeout=30000;
-	// 连接鲜活标记;
-	BOOL KeepAlive=TRUE;
-	// 请求的标记头;
-	std::string Accept="text/html, application/xhtml+xml, */*";
-	// 请求返回类型;
-	std::string ContentType= "text/html";
-	// 客户端访问信息;
-	std::string UserAgent= "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
-	// 返回数据的编码;
-	std::string Encoding;
-	// Post的数据类型;
-	std::string PostDataType;
-	// Post请求时要发送的数据;
-	std::string PostData;
-	// Cookie对象集合;
-	std::string CookieCollection;
-	// 请求时的Cookie;
-	std::string Cookie;
-	// 来源地址,上次访问的地址;
-	std::string Referer;
-	// 证书绝对路径;
-	std::string CerPath;
-	// 设置代理对象;
-	WINHTTP_CURRENT_USER_IE_PROXY_CONFIG WebProxy;
-	// 是否设置全文小写;
-	BOOL isToLower=FALSE;
-	// 获取或设置要在HTTP 请求中使用的Date HTTP标头值;
-	SYSTEMTIME Date;
-	// 支持跳转页面,查询结果将是跳转后的页面;
-	BOOL AllowAutoRedirect=FALSE;
-	// 最大连接数;
-	DWORD ConnectionLimit;
-	// 代理服务器用户名;
-	std::string ProxyUserName;
-	// 代理服务器密码;
-	std::string ProxyPwd;
-	// 代理服务器IP;
-	std::string ProxyIP;
-	// 设置返回类型String和Byte;
-	std::string ResultType;
-	// HTTP请求头Header对象;
-	std::string Header;
-	// 获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11
-	HTTP_VERSION_INFO ProtocolVersion;
-	// 获取或设置一个 System.Boolean 值,该值确定是否使用 100-Continue 行为。如果 POST 请求需要 100-Continue 响应,则为 true;否则为 false。默认值为 true
-	BOOL Expect100Continue=FALSE;
-	// 设置509证书集合;
-	std::string ClentCertificates;
-	// 设置或获取Post参数编码,默认的为Default编码;
-	std::string PostEncoding;
-	// Cookie返回类型,默认的是只返回字符串类型;
-	std::string ResultCookieType;
-	// 获取或设置请求的身份验证信息
-	std::string ICredentials;
-	// 设置请求将跟随的重定向的最大数目
-	DWORD MaximumAutomaticRedirections;
-	// 获取和设置IfModifiedSince,默认为当前日期和时间;
-	tm IfModifiedSince;
-	// 是否重置request,response的值,默认不重置,当设置为True时request,response将被设置为Null;
-	bool IsReset=FALSE;
-	// 设置本地的出口IP和端口;
-	std::string IPEndPoint;
+	
 #else
+	// 请求地址;
 	std::wstring m_strUrl;
 	// 主机;
 	std::wstring m_strHost;
@@ -144,12 +77,6 @@ typedef struct HTTPItem
 	std::wstring m_strMethod; // GET/POST/HEAD/PUT……;
 	// 客户端访问信息;
 	std::wstring m_strUserAgent;
-	// 连接鲜活标记;
-	BOOL m_bKeepAlive;
-	// 请求的标记头;
-	std::wstring m_strAccept;
-	// 请求返回类型;
-	std::wstring m_strContentType;	
 
 #pragma region 超时值设置;
 	// 域名解析超时值,默认值为0,表示无穷大;
@@ -183,30 +110,16 @@ typedef struct HTTPItem
 #pragma region 证书;
 
 #pragma endregion
-
-	
-	// 返回数据的编码;
-	std::wstring m_strEncoding;
-	// Post的数据类型;
-	std::wstring m_strPostDataType;
 	// Post请求时要发送的数据;
-	std::wstring m_strPostData;	
+	std::string m_strPostData;	
 	// 来源地址,上次访问的地址;
 	std::wstring m_strReferer;
 	// 证书绝对路径;
 	std::wstring m_strCerPath;
 	// 设置代理对象,不想使用IE默认配置就设置为Null,而且不要设置ProxyIp
 	WINHTTP_CURRENT_USER_IE_PROXY_CONFIG m_WebProxy;
-	// 是否设置全文小写;
-	BOOL m_bIsToLower;
-	// 获取或设置要在HTTP 请求中使用的Date HTTP标头值;
-	SYSTEMTIME m_Date;
 	// 支持跳转页面,查询结果将是跳转后的页面;
 	BOOL m_bAllowAutoRedirect;
-	// 最大连接数;
-	DWORD m_dwConnectionLimit;	
-	// 设置返回类型String和Byte;
-	std::string m_strResultType;
 	// HTTP请求头Header对象,多个头使用\r\n分隔;
 	std::wstring m_strHeader;
 	// 获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11
@@ -222,15 +135,9 @@ typedef struct HTTPItem
 	// 获取或设置请求的身份验证信息
 	std::wstring m_strICredentials;
 	// 设置请求将跟随的重定向的最大数目
-	DWORD m_dwMaximumAutomaticRedirections;
-	// 获取和设置IfModifiedSince,默认为当前日期和时间;
-	SYSTEMTIME m_IfModifiedSince;
-	// 是否重置request,response的值,默认不重置,当设置为True时request,response将被设置为Null;
-	bool m_bIsReset;
-	// 设置本地的出口IP和端口;
-	std::wstring m_strIPEndPoint;
+	//DWORD m_dwMaximumAutomaticRedirections;
 	// 表单数据;
-	std::wstring m_strFormData;
+	std::string m_strFormData;
 	// 查询参数;
 	std::wstring m_strQueryParams;
 
@@ -245,24 +152,13 @@ typedef struct HTTPItem
 		m_nSendTimeout = 30000;
 		// 接收超时值,默认30秒;
 		m_nReceiveTimeout = 30000;
-		// 默认连接鲜活;
-		m_bKeepAlive = TRUE;
-		// 默认请求头值;
-		m_strAccept = L"text/html, application/xhtml+xml, */*";
-		// 默认返回类型;
-		m_strContentType = L"text/html";
 		// 默认客户端访问信息值;
 		m_strUserAgent = L"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
-		// 返回数据默认编码类型utf-8;
-
-		// 默认不转小写;
-		m_bIsToLower = FALSE;
 		// 默认不跳转;
 		m_bAllowAutoRedirect = FALSE;
 		// 默认不继续;
 		m_bExpect100Continue = FALSE;
-		m_bIsReset = FALSE;
-
+		m_brequireValidSSL = FALSE;
 		m_ProtocolVersion.dwMajorVersion=1;
 		m_ProtocolVersion.dwMinorVersion=0;
 	}

+ 170 - 156
WINHTTPS/WINHTTPS/HTTPHelper.cpp

@@ -3,10 +3,20 @@
 
 HTTPHelper::HTTPHelper(void):m_hSession(NULL),m_hConnect(NULL),m_hRequest(NULL),m_nRetryTimes(3)
 {
+	/* 设置默认头值; */
+	AddRequestHeaders(L"Accept", L"*/*");
+	AddRequestHeaders(L"Connection", L"close");
+	AddRequestHeaders(L"Accept-Charset", L"UTF-8");
+	AddRequestHeaders(L"Cache-Control", L"no-cache");
+	AddRequestHeaders(L"User-Agent", L"WINHTTP-C++/1.0.01");
+	//AddRequestHeaders(L"Content-Type", L"application/json;charset=utf-8"); 
 }
 
 HTTPHelper::~HTTPHelper(void)
 {
+	if (NULL != m_hRequest) WinHttpCloseHandle(m_hRequest);
+	if (NULL != m_hConnect) WinHttpCloseHandle(m_hConnect);
+	if (NULL != m_hSession) WinHttpCloseHandle(m_hSession);
 }
 
 bool HTTPHelper::UrlParse(std::wstring strUrl)
@@ -47,9 +57,9 @@ bool HTTPHelper::UrlParse(std::wstring strUrl)
 	return FALSE;
 }
 
-bool HTTPHelper::GetHtml(HTTPITEM &item, HTTPRESULT &result)
+bool HTTPHelper::GetHtml(HTTPRESULT &result)
 {
-	if ( !SendRequest(item,result) )
+	if ( !SendRequest(result) )
 		return false;
 
 	return true;
@@ -84,21 +94,27 @@ BOOL HTTPHelper::_OpenHTTP()
 			return FALSE;
 		}
 
+		// 设置请求参数;
 		std::wstring strObjctName = m_strApiName;
 		if ( m_strQueryParams.size() ) {
 			strObjctName.append(L"?");
 			strObjctName.append(m_strQueryParams);
 		}
 
+		DWORD dwFlags = WINHTTP_FLAG_REFRESH;
 		// 请求类型:是否是https;
-		DWORD dwOpenRequestFlag = (m_nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0;
+		if ( m_nScheme == INTERNET_SCHEME_HTTPS ) {
+			// 启用ssl模式;
+			dwFlags |= WINHTTP_FLAG_SECURE;
+		}
+
 		m_hRequest = WinHttpOpenRequest(m_hConnect, 
 			m_strMethod.c_str(), 
 			strObjctName.c_str(),
-			NULL,
+			L"HTTP/1.1",
 			WINHTTP_NO_REFERER,
 			WINHTTP_DEFAULT_ACCEPT_TYPES,
-			dwOpenRequestFlag);
+			dwFlags);
 
 		if ( m_hRequest == NULL ) {
 			dwError = GetLastError();
@@ -106,12 +122,18 @@ BOOL HTTPHelper::_OpenHTTP()
 		}
 
 		// 如果是https,那么客户端就很容易受到无效证书的影响,现在接受任何事情都是最容易的
-		if ( m_brequireValidSSL && m_nScheme == INTERNET_SCHEME_HTTPS ) {
-			DWORD dwOps = SECURITY_FLAG_IGNORE_CERT_CN_INVALID
-				| SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
-				| SECURITY_FLAG_IGNORE_UNKNOWN_CA
-				| SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
-			WinHttpSetOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwOps, sizeof(DWORD));
+		//if ( m_brequireValidSSL && m_nScheme == INTERNET_SCHEME_HTTPS ) 
+		if ( m_nScheme == INTERNET_SCHEME_HTTPS ) 
+		{
+			DWORD dwBuffLen = sizeof(dwFlags);
+			WinHttpQueryOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen);
+			dwFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;//忽略ssl模式下的证书名称错误
+			dwFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
+			dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+			dwFlags |= SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
+			WinHttpSetOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
+			// 无证书的https;
+			//WinHttpSetOption(m_hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
 		}
 	}
 
@@ -146,95 +168,16 @@ BOOL HTTPHelper::_SendRequestData()
 
 		// 发送请求;
 		bool bSendRequestSucceed = false;
-		//if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, (LPVOID)m_strPostData.c_str(), m_strPostData.size()*sizeof(wchar_t), m_strPostData.size()*sizeof(wchar_t), NULL))
-		//if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, 0, _GetSendRequestSize(), NULL))
-		if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL)) // 这里不设置长度,就在Header Content-Length设置;
+
+		//if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, (LPVOID)data, data_len, data_len, NULL))
+		if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, 0, _GetSendRequestSize(), NULL))
+		//if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL)) // 这里不设置长度,就在Header Content-Length设置;
 		{
 			bSendRequestSucceed = true;
 		}
 		else
 		{
-			// 从IE设置中查询代理信息,如果有代理,设置代理;
-			WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
-			memset(&proxyConfig, 0, sizeof(proxyConfig));
-			if (::WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig))
-			{
-				if (proxyConfig.lpszAutoConfigUrl != NULL)
-				{
-					WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
-					memset(&autoProxyOptions, 0, sizeof(autoProxyOptions));
-					autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_CONFIG_URL;
-					autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP;
-					autoProxyOptions.lpszAutoConfigUrl = proxyConfig.lpszAutoConfigUrl;
-					autoProxyOptions.fAutoLogonIfChallenged = TRUE;
-					autoProxyOptions.dwReserved = 0;
-					autoProxyOptions.lpvReserved = NULL;
-
-					WINHTTP_PROXY_INFO proxyInfo;
-					memset(&proxyInfo, 0, sizeof(proxyInfo));
-
-					if (::WinHttpGetProxyForUrl(m_hSession, m_strUrl.c_str(), &autoProxyOptions, &proxyInfo))
-					{
-						if (::WinHttpSetOption(m_hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
-						{
-							if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL))
-							{
-								bSendRequestSucceed = true;
-							}
-						}
-						if (proxyInfo.lpszProxy != NULL)
-						{
-							::GlobalFree(proxyInfo.lpszProxy);
-						}
-						if (proxyInfo.lpszProxyBypass != NULL)
-						{
-							::GlobalFree(proxyInfo.lpszProxyBypass);
-						}
-					}
-					else
-					{
-						dwError = ::GetLastError();
-					}
-				}
-				else if (proxyConfig.lpszProxy != NULL)
-				{
-					WINHTTP_PROXY_INFO proxyInfo;
-					memset(&proxyInfo, 0, sizeof(proxyInfo));
-					proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
-					wchar_t szProxy[MAX_PATH] = L"";
-					wcscpy_s(szProxy, MAX_PATH, proxyConfig.lpszProxy);
-					proxyInfo.lpszProxy = szProxy;
-
-					if (proxyConfig.lpszProxyBypass != NULL)
-					{
-						wchar_t szProxyBypass[MAX_PATH] = L"";
-						wcscpy_s(szProxyBypass, MAX_PATH, proxyConfig.lpszProxyBypass);
-						proxyInfo.lpszProxyBypass = szProxyBypass;
-					}
-
-					if (!::WinHttpSetOption(m_hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
-					{
-						dwError = ::GetLastError();
-					}
-				}
-
-				if (proxyConfig.lpszAutoConfigUrl != NULL)
-				{
-					::GlobalFree(proxyConfig.lpszAutoConfigUrl);
-				}
-				if (proxyConfig.lpszProxy != NULL)
-				{
-					::GlobalFree(proxyConfig.lpszProxy);
-				}
-				if (proxyConfig.lpszProxyBypass != NULL)
-				{
-					::GlobalFree(proxyConfig.lpszProxyBypass);
-				}
-			}
-			else
-			{
-				dwError = ::GetLastError();
-			}
+			bSendRequestSucceed = _SetIEProxy();
 		}
 
 		if (bSendRequestSucceed)
@@ -243,7 +186,8 @@ BOOL HTTPHelper::_SendRequestData()
 			if ( m_strFormData.size() != 0 )
 			{
 				DWORD dwWritten = 0;
-				if (!::WinHttpWriteData(m_hRequest, m_strFormData.c_str(), m_strFormData.size()*sizeof(wchar_t), &dwWritten))
+				// 使用WinHttpWriteData时,必须在WinHttpSendRequest中指定Data的大小;在Header中好像无效;
+				if (!::WinHttpWriteData(m_hRequest, m_strFormData.c_str(), m_strFormData.size(), &dwWritten))
 				{
 					dwError = ::GetLastError();
 					continue;
@@ -254,7 +198,8 @@ BOOL HTTPHelper::_SendRequestData()
 			if ( m_strPostData.size() != 0 )
 			{
 				DWORD dwWritten = 0;
-				if (!::WinHttpWriteData(m_hRequest, m_strPostData.c_str(), m_strPostData.size()*sizeof(wchar_t), &dwWritten))
+				// 使用WinHttpWriteData时,必须在WinHttpSendRequest中指定Data的大小;在Header中好像无效;
+				if (!::WinHttpWriteData(m_hRequest, m_strPostData.c_str(), m_strPostData.size(), &dwWritten))
 				{
 					dwError = ::GetLastError();
 					continue;
@@ -306,6 +251,7 @@ BOOL HTTPHelper::_ReceiveResponse(std::wstring &strHeaer, DWORD &dwStatusCode, s
 		}
 
 		dwSize = 0;
+		// 获取返回状态大小;
 		bResult = ::WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX); 
 		if (bResult || (!bResult && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)))
 		{
@@ -316,12 +262,10 @@ BOOL HTTPHelper::_ReceiveResponse(std::wstring &strHeaer, DWORD &dwStatusCode, s
 			}
 		}
 		
-		if ( dwStatusCode != 200 )
-			return FALSE;
-
 		do
 		{
 			dwSize = 0;
+			// 查询是否有可用数据;
 			if (WinHttpQueryDataAvailable(m_hRequest, &dwSize))
 			{
 				if (dwSize==0)
@@ -348,7 +292,7 @@ BOOL HTTPHelper::_ReceiveResponse(std::wstring &strHeaer, DWORD &dwStatusCode, s
 	return TRUE;
 }
 
-bool HTTPHelper::SendRequest(HTTPITEM &item,HTTPRESULT &httpResult)
+bool HTTPHelper::SendRequest(HTTPRESULT &httpResult)
 {
 	if (!_OpenHTTP())
 		return false;
@@ -386,9 +330,9 @@ BOOL HTTPHelper::_SetRequestHeaders()
 		return FALSE;
 
 	if ( m_strHeader.size() > 0 ) {
-#if 1 // WinHttpSendRequest里不设置数据长度,这里必须设置;
+#if 0 // WinHttpSendRequest里不设置数据长度,这里必须设置;
 		wchar_t szContentLength[MAX_PATH] = {0};
-		swprintf_s(szContentLength, L"%s%d\r\n", CONTENT_LENGTH, _GetSendRequestSize());
+		swprintf_s(szContentLength, L"%s: %d\r\n", CONTENT_LENGTH, _GetSendRequestSize());
 		m_strHeader.append(szContentLength);
 #endif
 		if ( !WinHttpAddRequestHeaders(m_hRequest, m_strHeader.c_str(), m_strHeader.size(), WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON) ) {
@@ -402,7 +346,7 @@ BOOL HTTPHelper::_SetRequestHeaders()
 
 void HTTPHelper::_SetContentLength()
 {
-	int nPos = m_strHeader.find(CONTENT_LENGTH);
+	int nPos = m_strHeader.find(L"Content-Length: ");
 	if ( nPos != std::wstring::npos) {
 		// 删除原有的请求头;
 		int nPos2 = m_strHeader.find(L"\r\n",nPos);
@@ -413,7 +357,7 @@ void HTTPHelper::_SetContentLength()
 	}
 
 	wchar_t szContentLenght[MAX_PATH] = {0};
-	swprintf_s(szContentLenght, L"%s%d", CONTENT_LENGTH, m_strFormData.size());
+	swprintf_s(szContentLenght, L"%s: %d", L"Content-Length", m_strFormData.size());
 
 	// 添加Form表单头;
 	m_strHeader.append(szContentLenght);
@@ -424,9 +368,9 @@ DWORD HTTPHelper::_GetSendRequestSize()
 {
 	DWORD dwSize(0);
 	if ( m_strPostData.size())
-		dwSize = m_strPostData.size()*sizeof(wchar_t);
+		dwSize = m_strPostData.size();
 	else if ( m_strFormData.size())
-		dwSize = m_strFormData.size()*sizeof(wchar_t);
+		dwSize = m_strFormData.size();
 
 	return dwSize;
 }
@@ -486,6 +430,95 @@ BOOL HTTPHelper::_SetProxy()
 	return TRUE;
 }
 
+BOOL HTTPHelper::_SetIEProxy()
+{
+	// 从IE设置中查询代理信息,如果有代理,设置代理;
+	DWORD dwError(0);
+	BOOL bSendRequestSucceed=FALSE;
+	WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
+	memset(&proxyConfig, 0, sizeof(proxyConfig));
+	if (::WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig))
+	{
+		if (proxyConfig.lpszAutoConfigUrl != NULL)
+		{
+			WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
+			memset(&autoProxyOptions, 0, sizeof(autoProxyOptions));
+			autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_CONFIG_URL;
+			autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP;
+			autoProxyOptions.lpszAutoConfigUrl = proxyConfig.lpszAutoConfigUrl;
+			autoProxyOptions.fAutoLogonIfChallenged = TRUE;
+			autoProxyOptions.dwReserved = 0;
+			autoProxyOptions.lpvReserved = NULL;
+
+			WINHTTP_PROXY_INFO proxyInfo;
+			memset(&proxyInfo, 0, sizeof(proxyInfo));
+
+			if (::WinHttpGetProxyForUrl(m_hSession, m_strUrl.c_str(), &autoProxyOptions, &proxyInfo))
+			{
+				if (::WinHttpSetOption(m_hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
+				{
+					if (::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL))
+					{
+						bSendRequestSucceed = true;
+					}
+				}
+				if (proxyInfo.lpszProxy != NULL)
+				{
+					::GlobalFree(proxyInfo.lpszProxy);
+				}
+				if (proxyInfo.lpszProxyBypass != NULL)
+				{
+					::GlobalFree(proxyInfo.lpszProxyBypass);
+				}
+			}
+			else
+			{
+				dwError = ::GetLastError();
+			}
+		}
+		else if (proxyConfig.lpszProxy != NULL)
+		{
+			WINHTTP_PROXY_INFO proxyInfo;
+			memset(&proxyInfo, 0, sizeof(proxyInfo));
+			proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+			wchar_t szProxy[MAX_PATH] = L"";
+			wcscpy_s(szProxy, MAX_PATH, proxyConfig.lpszProxy);
+			proxyInfo.lpszProxy = szProxy;
+
+			if (proxyConfig.lpszProxyBypass != NULL)
+			{
+				wchar_t szProxyBypass[MAX_PATH] = L"";
+				wcscpy_s(szProxyBypass, MAX_PATH, proxyConfig.lpszProxyBypass);
+				proxyInfo.lpszProxyBypass = szProxyBypass;
+			}
+
+			if (!::WinHttpSetOption(m_hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
+			{
+				dwError = ::GetLastError();
+			}
+		}
+
+		if (proxyConfig.lpszAutoConfigUrl != NULL)
+		{
+			::GlobalFree(proxyConfig.lpszAutoConfigUrl);
+		}
+		if (proxyConfig.lpszProxy != NULL)
+		{
+			::GlobalFree(proxyConfig.lpszProxy);
+		}
+		if (proxyConfig.lpszProxyBypass != NULL)
+		{
+			::GlobalFree(proxyConfig.lpszProxyBypass);
+		}
+	}
+	else
+	{
+		dwError = ::GetLastError();
+	}
+
+	return bSendRequestSucceed;
+}
+
 BOOL HTTPHelper::_SetAutoRedirect()
 {
 	if ( !m_bAllowAutoRedirect ) {
@@ -499,22 +532,6 @@ BOOL HTTPHelper::_SetAutoRedirect()
 	return TRUE;
 }
 
-void HTTPHelper::SetContentType(std::wstring strContentType)
-{
-	int nPos = m_strHeader.find(CONTENT_TYPE);
-	if ( nPos != std::wstring::npos) {
-		// 删除原有的请求头;
-		int nPos2 = m_strHeader.find(L"\r\n",nPos);
-		if ( nPos2 !=std::wstring::npos )
-			m_strHeader.erase(nPos, nPos2-nPos+2);
-		else
-			m_strHeader.erase(nPos);
-	}
-	// 添加Form表单头;
-	m_strHeader.append(strContentType);
-	m_strHeader.append(CRLF);
-}
-
 void HTTPHelper::AddQueryParams(std::wstring strName, std::wstring strValue)
 {
 	if ( m_strQueryParams.size() )
@@ -567,93 +584,90 @@ void HTTPHelper::AddFormUrlEncodedDataHeader()
 	m_strFormData.clear();
 }
 
-void HTTPHelper::AddBodyFormDataText(std::wstring strName, std::wstring strValue)
+void HTTPHelper::AddBodyFormDataText(std::string strName, std::string strValue)
 {
 	AddFormDataHeader();//放到外头,只调用一次就好;
-	int nSize = wcslen(FORMDATA_TEXT_FORMAT) + strName.size() + strValue.size();
+	int nSize = strlen(FORMDATA_TEXT_FORMAT) + strName.size() + strValue.size();
 	if ( nSize < K0 ) {
-		wchar_t szFormData[K0] = {0};
-		swprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
+		char szFormData[K0] = {0};
+		sprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K1 ) {
-		wchar_t szFormData[K1] = {0};
-		swprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
+		char szFormData[K1] = {0};
+		sprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K2 ) {
-		wchar_t szFormData[K2] = {0};
-		swprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
+		char szFormData[K2] = {0};
+		sprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K4 ) {
-		wchar_t szFormData[K4] = {0};
-		swprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
+		char szFormData[K4] = {0};
+		sprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K8 ) {
-		wchar_t szFormData[K8] = {0};
-		swprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
+		char szFormData[K8] = {0};
+		sprintf_s(szFormData, FORMDATA_TEXT_FORMAT, strName.c_str(), strName.c_str(), strValue.c_str());
 		m_strFormData.append(szFormData);
 	} else {
-
+		// new
 	}
 }
 
-void HTTPHelper::AddBodyFormDataFile(std::wstring strName, std::wstring strFilePath, std::wstring strContentType)
+void HTTPHelper::AddBodyFormDataFile(std::string strName, std::string strFilePath, std::wstring strContentType)
 {
 	AddFormDataHeader();//放到外头,只调用一次就好;
-	int nSize = wcslen(FORMDATA_FILE_FORMAT) + strName.size() + strFilePath.size() + strContentType.size();
+	int nSize = strlen(FORMDATA_FILE_FORMAT) + strName.size() + strFilePath.size() + strContentType.size();
 	if ( nSize < K0 ) {
-		wchar_t szFormData[K0] = {0};
-		swprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
+		char szFormData[K0] = {0};
+		sprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K1 ) {
-		wchar_t szFormData[K1] = {0};
-		swprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
+		char szFormData[K1] = {0};
+		sprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K2 ) {
-		wchar_t szFormData[K2] = {0};
-		swprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
+		char szFormData[K2] = {0};
+		sprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K4 ) {
-		wchar_t szFormData[K4] = {0};
-		swprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
+		char szFormData[K4] = {0};
+		sprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
 		m_strFormData.append(szFormData);
 	}
 	else if ( nSize < K8 ) {
-		wchar_t szFormData[K8] = {0};
-		swprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
+		char szFormData[K8] = {0};
+		sprintf_s(szFormData, FORMDATA_FILE_FORMAT, strName.c_str(), strName.c_str(), strFilePath.c_str(), strContentType.c_str());
 		m_strFormData.append(szFormData);
 	} else {
 
 	}
 }
 
-void HTTPHelper::AddBodyFormUrlEncodedData(std::wstring strName, std::wstring strValue)
+void HTTPHelper::AddBodyFormUrlEncodedData(std::string strName, std::string strValue)
 {
 	AddFormUrlEncodedDataHeader();//放到外头,只调用一次就好;
 	if ( m_strFormData.size() )
-		m_strFormData.append(L"&");
+		m_strFormData.append("&");
 
 	m_strFormData.append(strName);
-	m_strFormData.append(L"=");
+	m_strFormData.append("=");
 	m_strFormData.append(strValue);
 	// 重新计算长度;
 	_SetContentLength();
 }
 
-void HTTPHelper::AddBodyRawData(std::wstring strRawData, std::wstring strContentType/* = */)
+void HTTPHelper::AddBodyRawData(std::string strRawData, std::wstring strContentType/* = */)
 {
 	m_strPostData = strRawData;
 	// 代替ContentType
-	strRawData = CONTENT_TYPE;
-	strRawData.append(strContentType);
-	strRawData.append(CRLF);
-	SetContentType(strRawData);
+	AddRequestHeaders(CONTENT_TYPE, strContentType);
 }
 
 void HTTPHelper::AddBodyBinary(std::wstring strFilePath)

+ 10 - 11
WINHTTPS/WINHTTPS/HTTPHelper.h

@@ -15,6 +15,7 @@ public:
 
 private:	
 	BOOL _SetProxy();
+	BOOL _SetIEProxy();
 	BOOL _SetCookies();
 	BOOL _SetTimeout();
 	BOOL _SetAutoRedirect();
@@ -27,30 +28,28 @@ private:
 	
 public:
 	bool UrlParse(std::wstring strUrl=L"");
-	bool GetHtml(HTTPITEM &item, HTTPRESULT &result);
-	bool SendRequest(HTTPITEM &item, HTTPRESULT &result);
+	bool GetHtml(HTTPRESULT &result);
+	bool SendRequest(HTTPRESULT &result);
 
 public:
-	void SetContentType(std::wstring strContentType);
 	// 添加查询参数;
 	void AddQueryParams(std::wstring strName, std::wstring strValue);
-	
 #pragma region Body类型,只能使用其中一种方式
 	void AddFormDataHeader();
 	void AddFormUrlEncodedDataHeader();
 	// 设置Body:得先调用AddFormDataHeader、AddFormUrlEncodedDataHeader;
-	void AddBodyFormDataText(std::wstring strName, std::wstring strValue);
-	void AddBodyFormDataFile(std::wstring strName, std::wstring strFilePath, std::wstring strContentType=L"image/gif");
-	void AddBodyFormUrlEncodedData(std::wstring strName, std::wstring strValue);
+	void AddBodyFormDataText(std::string strName, std::string strValue);
+	void AddBodyFormDataFile(std::string strName, std::string strFilePath, std::wstring strContentType=L"image/gif");
+	void AddBodyFormUrlEncodedData(std::string strName, std::string strValue);
 	// 原始数据,需要在请求头指定数据类型,如json、xml格式内容;
-	void AddBodyRawData(std::wstring strRawData, std::wstring strContentType=L"*/*");
+	void AddBodyRawData(std::string strRawData, std::wstring strContentType=L"*/*");
 	// 上传二进制,需要指定文件名;
 	void AddBodyBinary(std::wstring strFilePath);
 #pragma endregion
 	// 设置Post的数据;
-	void SetPostData(std::wstring strPostData) {m_strPostData = strPostData;};
+	//void SetPostData(std::wstring strPostData) {m_strPostData = strPostData;};
 	// 设置表单数据;
-	void SetFormData(std::wstring strFormData) {m_strFormData = strFormData;};
+	void SetFormData(std::string strFormData) {m_strFormData = strFormData;};
 	// 设置上传的文件;
 	void SetUploadFile(std::wstring strFileName);
 	// 设置url;
@@ -66,7 +65,7 @@ public:
 	// 设置Cookie;
 	inline void SetCookies(std::wstring strCookies){ m_strCookies = strCookies; };
 	// 设置用户代理;
-	inline void SetUserAgent(std::wstring strAgent=L"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)") { m_strUserAgent = strAgent;};
+	inline void SetUserAgent(std::wstring strAgent=L"WINHTTP-C++/1.0.01") { m_strUserAgent = strAgent;};
 	// 设置代理;
 	inline void SetProxy(std::wstring strProxyServerList, std::wstring strProxyUserName=L"", std::wstring strProxyPwd=L"") {
 		m_strProxyPwd = strProxyPwd;

+ 124 - 151
WINHTTPS/WINHTTPS/WINHTTPS.cpp

@@ -8,22 +8,31 @@
 
 void test_get()
 {
-	HTTPITEM itme;
 	HTTPRESULT result;
-
 	HTTPHelper hhelper;
 	hhelper.SetMethod(L"POST");
+	// 用来指定当前的请求/回复中的,是否使用缓存机制
 	//hhelper.AddRequestHeaders(L"Cache-Control", L"no-cache");
+	// 发送请求的客户端的类型
 	hhelper.AddRequestHeaders(L"User-Agent", L"Moka_Factory/1.0.01");
+	// 可接受的字符集;
+	//hhelper.AddRequestHeaders(L"Accept-Charset", L"UTF-8");
+	//可接受的响应内容类型
 	//hhelper.AddRequestHeaders(L"Accept", L"*/*");
+	// 可接受的响应内容的编码方式
 	//hhelper.AddRequestHeaders(L"Accept-Encoding", L"gzip, deflate, br");
+	// 可接受的响应内容语言列表
+	//hhelper.AddRequestHeaders(L"Accept-Language", L"?");
+	// 客户端(浏览器)想要优先使用的连接类型
 	hhelper.AddRequestHeaders(L"Connection", L"keep-alive");
+	// 请求的报文格式
+	//hhelper.AddRequestHeaders(L"Content-type", L"?");
 	//hhelper.SetUrl(L"http://huizhou.idmanage.qhmoka.com/IDManage/getid.do?devicetype=SCBC_RT2851M&sn=DGG75095762111001764&order=DGG7509576");
 	hhelper.SetUrl(L"http://huizhou.idmanage.qhmoka.com/IDManage/getid.do");
 	hhelper.AddQueryParams(L"devicetype", L"SCBC_RT2851M");
 	hhelper.AddQueryParams(L"sn", L"DGG75095762111001764");
 	hhelper.AddQueryParams(L"order", L"DGG7509576");
-	hhelper.GetHtml(itme,result);
+	hhelper.GetHtml(result);
 
 	wprintf(L"ResponseHeader=%s\r\n",result.m_strHeader.c_str());
 	wprintf(L"StatusCode=%ld\r\n", result.m_dwStatusCode);
@@ -36,9 +45,7 @@ void test_get()
 
 void test_post()
 {
-	HTTPITEM itme;
 	HTTPRESULT result;
-
 	HTTPHelper hhelper;
 	hhelper.SetMethod(L"POST");
 	//hhelper.AddRequestHeaders(L"Cache-Control", L"no-cache");
@@ -56,8 +63,41 @@ void test_post()
 	//hhelper.AddRequestHeaders(L"Content-Length", L"755"); // POST时才需要用到
 	hhelper.SetUrl(L"http://test.scbc.qhmoka.com/scbc-server/clientType/getMessage.do");
 	//hhelper.SetPostData(L"{\"bid\":\"TEST_WJF\",\"mac\":\"04-D4-C4-EE-6B-CD\"}");
-	hhelper.AddBodyRawData(L"{\"bid\":\"TEST_WJF\",\"mac\":\"04-D4-C4-EE-6B-CD\"}", L"application/json");
-	hhelper.GetHtml(itme,result);
+	hhelper.AddBodyRawData("{\"bid\":\"TEST_WJF\",\"mac\":\"04-D4-C4-EE-6B-CD\"}", L"application/json");
+	hhelper.GetHtml(result);
+
+	wprintf(L"ResponseHeader=%s\r\n",result.m_strHeader.c_str());
+	wprintf(L"StatusCode=%ld\r\n", result.m_dwStatusCode);
+
+	if (result.m_dwStatusCode == 200)
+		printf("ResponseData=%s\r\n",result.m_strResponseData.c_str());
+
+	system("pause");
+
+	int a = 0;
+}
+
+void test_post1()
+{
+	HTTPRESULT result;
+	HTTPHelper hhelper;
+	hhelper.SetMethod(L"POST");
+	hhelper.AddRequestHeaders(L"Cache-Control", L"no-cache");
+	hhelper.AddRequestHeaders(L"User-Agent", L"Moka_Factory/1.0.01");
+	hhelper.AddRequestHeaders(L"Accept", L"*/*");
+#pragma region 造成Post时返回分块编码的原因是:Accept-Encoding中gzip造成数据压缩传输了.
+	hhelper.AddRequestHeaders(L"Accept-Encoding", L"gzip, deflate, br");
+	hhelper.AddRequestHeaders(L"Connection", L"keep-alive");
+	//hhelper.AddRequestHeaders(L"Connection", L"close"); //关闭,也一样会产生会分块编码(Transfer-Encoding: chunked)
+	//hhelper.AddRequestHeaders(L"Transfer-Encoding", L""); //关闭,也一样会产生会分块编码(Transfer-Encoding: chunked)
+#pragma endregion
+	//content-encoding
+	//hhelper.AddRequestHeaders(L"Content-Encoding", L"UTF-8"); // POST时才需要用到;
+	//hhelper.AddRequestHeaders(L"Content-Type", L"application/json;charset=utf8"); // POST时才需要用到;
+	//hhelper.AddRequestHeaders(L"Content-Length", L"755"); // POST时才需要用到
+	hhelper.SetUrl(L"http://test.idmanage.qhmoka.com/IDManage/v2/bind/order");
+	hhelper.AddBodyRawData("{\"orderNum\":\"TEST_WJF\",\"sn\":\"SN0321-test9999\",\"psn\":\"20220321APSN9999\",\"orderCode\":\"BBB\",\"skipKey\": []}", L"application/json;charset=utf8");
+	hhelper.GetHtml(result);
 
 	wprintf(L"ResponseHeader=%s\r\n",result.m_strHeader.c_str());
 	wprintf(L"StatusCode=%ld\r\n", result.m_dwStatusCode);
@@ -72,159 +112,92 @@ void test_post()
 
 void test_download()
 {
+	//http://szidmanage.file.qhmoka.com/JsonFile/SanHua/20220718091143128.json
+	//https://bbs.pediy.com/attach-download-197174-8975e845ab91d7d04fee9d527f739f6d@v9DMStXlWsHI08Zl2C_2FIqg_3D_3D.htm
+	HTTPRESULT result;
+	HTTPHelper hhelper;
+	hhelper.SetMethod(L"GET");
+	hhelper.AddRequestHeaders(L"Cache-Control", L"no-cache");
+	hhelper.AddRequestHeaders(L"User-Agent", L"Moka_Factory/1.0.01");
+	hhelper.AddRequestHeaders(L"Accept", L"*/*");
+	//hhelper.AddRequestHeaders(L"Accept-Encoding", L"gzip, deflate, br");
+	//hhelper.AddRequestHeaders(L"Connection", L"keep-alive");//持续连接,会产生分块编码(Transfer-Encoding: chunked)
+	hhelper.AddRequestHeaders(L"Connection", L"close"); //关闭,也一样会产生会分块编码(Transfer-Encoding: chunked)
+	//content-encoding
+	//hhelper.AddRequestHeaders(L"Content-Encoding", L"UTF-8"); // POST时才需要用到;
+	//hhelper.AddRequestHeaders(L"Content-Type", L"application/json;charset=utf8"); // POST时才需要用到;
+	//hhelper.AddRequestHeaders(L"Content-Length", L"755"); // POST时才需要用到
+	//hhelper.SetUrl(L"http://szidmanage.file.qhmoka.com/JsonFile/SanHua/20220718091143128.json");
+	hhelper.SetUrl(L"https://codown.youdao.com/cidian/static/9.0/20220608/YoudaoDictSetup.exe");
+	hhelper.SetTimeout(0,60000,60000,120000);
+	//hhelper.SetPostData(L"{\"bid\":\"TEST_WJF\",\"mac\":\"04-D4-C4-EE-6B-CD\"}");
+	//hhelper.AddBodyRawData(L"{\"bid\":\"TEST_WJF\",\"mac\":\"04-D4-C4-EE-6B-CD\"}", L"application/json");
+	hhelper.GetHtml(result);
+
+	wprintf(L"ResponseHeader=%s\r\n",result.m_strHeader.c_str());
+	wprintf(L"StatusCode=%ld\r\n", result.m_dwStatusCode);
+
+	if (result.m_dwStatusCode == 200)
+		printf("ResponseData=%s\r\n",result.m_strResponseData.c_str());
+
+	system("pause");
+}
+
+void test_login()
+{
+	HTTPRESULT res;
+	HTTPHelper http;
+	http.SetMethod(L"POST");
+	//http.SetUrl(L"http://test.scbc.qhmoka.com/scbc-server/login.do"); 
+	http.SetUrl(L"https://cn.uc.qhmoka.com/scbc-server/login.do");
+	http.AddBodyRawData("{\"account\":\"SanHua\",\"password\":\"admin\",\"mac\":\"A0-00-00-00-00-0A\"}", L"application/json;charset=utf-8");
+	
+	http.GetHtml(res);
+
+	wprintf(L"ResponseHeader=%s\r\n",res.m_strHeader.c_str());
+	wprintf(L"StatusCode=%ld\r\n", res.m_dwStatusCode);
+
+	if (res.m_dwStatusCode == 200)
+		printf("ResponseData=%s\r\n",res.m_strResponseData.c_str());
 
+	system("pause");
 }
 
-void test_putfile()
+void test_updateCheck()
 {
+	HTTPRESULT res;
+	HTTPHelper http;
+	http.SetMethod(L"POST");
+	//http.AddRequestHeaders(L"Accept", L"application/json");
+	//http.AddRequestHeaders(L"User-Agent", L"Moka_Factory/1.0.01");
+	http.AddRequestHeaders(L"Content-Type", L"application/json");
+	//http.SetUrl(L"https://test.uc.qhmoka.com/ota-services/upmp/upgradeIncrForTool"); 
+	http.SetUrl(L"https://cn.ota.qhmoka.com/ota-services/upmp/upgradeIncrForTool");
+	//http.SetUrl(L"https://cn.uc.qhmoka.com/scbc-server/clientType/getMessage.do");
+	http.AddBodyRawData("{\"appid\":\"SCBC_Factory_Tools\",\"devicemodel\":\"SCBC_Factory_Tools\",\"dnum\":\"111\",\"ver\":\"3.0.6.4\",\"type\":\"pc\"}", L"application/json;charset=utf-8");
+	//http.AddBodyRawData(L"{\"clientType\":\"\",\"version\":\"\",\"bid\":\"IDE963353D\",\"mac\":\"94-DE-80-AA-CE-C9\"}", L"application/json;charset=utf-8");
+
+	http.GetHtml(res);
+
+	wprintf(L"ResponseHeader=%s\r\n",res.m_strHeader.c_str());
+	wprintf(L"StatusCode=%ld\r\n", res.m_dwStatusCode);
+
+	if (res.m_dwStatusCode == 200)
+		printf("ResponseData=%s\r\n",res.m_strResponseData.c_str());
 
+	system("pause");
 }
 
-int _tmain(int argc, _TCHAR* argv[])
+
+void test()
 {
-	test_get();
-	test_post();
-
-	HTTPITEM itme;
-	HINTERNET hSession = NULL;
-	HINTERNET hConnect = NULL;
-	HINTERNET hRequest = NULL;
-
-	URL_COMPONENTS urlComp;
-	// Initialize the URL_COMPONENTS structure.
-	ZeroMemory(&urlComp, sizeof(urlComp));
-	urlComp.dwStructSize = sizeof(urlComp);
-
-	// Set required component lengths to non-zero 
-	// so that they are cracked.
-	urlComp.dwSchemeLength    = (DWORD)-1;
-	urlComp.dwHostNameLength  = (DWORD)-1;
-	urlComp.dwUrlPathLength   = (DWORD)-1;
-	urlComp.dwExtraInfoLength = (DWORD)-1;
-
-	//std::wstring url = L"http://search.msn.com/results.asp?RS=CHECKED&FORM=MSNH&v=1&q=wininet";
-	std::wstring url = L"https://test.scbc.qhmoka.com/scbc-server/clientType/getMessage";
-	if (::WinHttpCrackUrl(url.c_str(), url.size(), ICU_REJECT_USERPWD, &urlComp))
-	{
-	}
-
-	//1. 初始化一个WinHTTP-session句柄,参数1为此句柄的名称
-	hSession = WinHttpOpen(L"idm-interface", NULL, NULL, NULL, NULL);
-	if (hSession == NULL) {
-		std::cout<<"Error:Open session failed: "<<GetLastError()<<std::endl;
-		return -1;
-	}
-
-	// http://test.scbc.qhmoka.com/scbc-server/clientType/getMessage.do
-	//2. 通过上述句柄连接到服务器,需要指定服务器IP和端口号。若连接成功,返回的hConnect句柄不为NULL
-	hConnect = WinHttpConnect(hSession, L"test.scbc.qhmoka.com", (INTERNET_PORT)urlComp.nPort, 0);
-	if (hConnect == NULL) {
-		std::cout << "Error:Connect failed: " << GetLastError()<<std::endl;
-		return -1;
-	}
-
-	//3. 通过hConnect句柄创建一个hRequest句柄,用于发送数据与读取从服务器返回的数据。
-	hRequest = WinHttpOpenRequest(hConnect, L"Post", L"scbc-server/clientType/getMessage.do", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
-	//其中参数2表示请求方式,此处为Post;参数3:给定Post的具体地址,如这里的具体地址为http://192.168.50.112/getServiceInfo
-	if (hRequest == NULL) {
-		std::cout << "Error:OpenRequest failed: " << GetLastError() << std::endl;
-		return -1;
-	}
-
-	//4-1. 向服务器发送post数据
-	//(1) 指定发送的数据内容
-	std::string data = "{\"bid\":\"Testdddd11111\",\"mac\":\"18-87-D5-E2-9A-55\",\"version\":\"\",\"clientType\":\"\"}"; 
-	const void *ss = (const char *)data.c_str();
-
-	//(2) 发送请求
-	BOOL bResults;
-	bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, const_cast<void*>(ss), data.length(), data.length(), 0);
-	if (!bResults){
-		std::cout << "Error:SendRequest failed: " << GetLastError() << std::endl;
-		return -1;
-	}
-	else{
-		//(3) 发送请求成功则准备接受服务器的response。注意:在使用 WinHttpQueryDataAvailable和WinHttpReadData前必须使用WinHttpReceiveResponse才能access服务器返回的数据
-		bResults = WinHttpReceiveResponse(hRequest, NULL);
-	}
-
-	//4-2. 获取服务器返回数据的header信息。这一步我用来获取返回数据的数据类型。
-	LPVOID lpHeaderBuffer = NULL;
-	DWORD dwSize = 0;   
-	if (bResults)
-	{
-		//(1) 获取header的长度
-		WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
-			WINHTTP_HEADER_NAME_BY_INDEX, NULL,
-			&dwSize, WINHTTP_NO_HEADER_INDEX);
-
-		//(2) 根据header的长度为buffer申请内存空间
-		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-		{
-			lpHeaderBuffer = new WCHAR[dwSize / sizeof(WCHAR)];
-
-			//(3) 使用WinHttpQueryHeaders获取header信息
-			bResults = WinHttpQueryHeaders(hRequest,
-				WINHTTP_QUERY_RAW_HEADERS_CRLF,
-				WINHTTP_HEADER_NAME_BY_INDEX,
-				lpHeaderBuffer, &dwSize,
-				WINHTTP_NO_HEADER_INDEX);
-		}
-	}
-	printf("Header contents: \n%S", lpHeaderBuffer);
-
-	//解析上述header信息会发现服务器返回数据的charset为uft-8。这意味着后面需要对获取到的raw data进行宽字符转换。一开始由于没有意识到需要进行转换所以得到的数据都是乱码。
-	//出现乱码的原因是:HTTP在传输过程中是二值的,它并没有text或者是unicode的概念。HTTP使用7bit的ASCII码作为HTTP headers,但是内容是任意的二值数据,需要根据header中指定的编码方式来描述它(通常是Content-Type header).
-	//因此当你接收到原始的HTTP数据时,先将其保存到char[] buffer中,然后利用WinHttpQueryHearders()获取HTTP头,得到内容的Content-Type,这样你就知道数据到底是啥类型的了,是ASCII还是Unicode或者其他。
-	//一旦你知道了具体的编码方式,你就可以通过MultiByteToWideChar()将其转换成合适编码的字符,存入wchar_t[]中。
-	//关于乱码的解决方案请看4-4
-
-	//4-3. 获取服务器返回数据
-	LPSTR pszOutBuffer = NULL;
-	DWORD dwDownloaded = 0;         //实际收取的字符数
-	wchar_t *pwText = NULL;
-	if (bResults)
-	{
-		do
-		{
-			//(1) 获取返回数据的大小(以字节为单位)
-			dwSize = 0;
-			if (!WinHttpQueryDataAvailable(hRequest, &dwSize)){
-				std::cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << std::endl;
-				break;
-			}           
-			if (!dwSize)    break;  //数据大小为0                
-
-			//(2) 根据返回数据的长度为buffer申请内存空间
-			pszOutBuffer = new char[dwSize + 1];
-			if (!pszOutBuffer){
-				std::cout<<"Out of memory."<<std::endl;
-				break;
-			}
-			ZeroMemory(pszOutBuffer, dwSize + 1);       //将buffer置0
-
-			//(3) 通过WinHttpReadData读取服务器的返回数据
-			if (!WinHttpReadData(hRequest,pszOutBuffer, dwSize, &dwDownloaded)){
-				std::cout << "Error:WinHttpQueryDataAvailable failed:" << GetLastError() << std::endl;
-			}
-			if (!dwDownloaded)
-				break;
-
-		} while (dwSize > 0);
-
-		//4-4. 将返回数据转换成UTF8
-		DWORD dwNum = MultiByteToWideChar(CP_ACP, 0, pszOutBuffer, -1, NULL, 0);    //返回原始ASCII码的字符数目       
-		pwText = new wchar_t[dwNum];                                                //根据ASCII码的字符数分配UTF8的空间
-		MultiByteToWideChar(CP_UTF8, 0, pszOutBuffer, -1, pwText, dwNum);           //将ASCII码转换成UTF8
-		printf("Received contents: \n%S", pwText);
-	}
-
-
-	//5. 依次关闭request,connect,session句柄
-	if (hRequest) WinHttpCloseHandle(hRequest);
-	if (hConnect) WinHttpCloseHandle(hConnect);
-	if (hSession) WinHttpCloseHandle(hSession);
+	test_login();
+	test_updateCheck();
+}
 
+int _tmain(int argc, _TCHAR* argv[])
+{
+	test();
 	return 0;
 }