功能齐全的 Windows HTTP 包装器(C++)
一个功能齐全且易于使用的 C++ Windows HTTP 包装器。
引言
这是一个全功能的 Windows HTTP 封装器,使用 C++ 开发。它是一个 C++ 类的封装器,功能齐全且易于使用。您只需要包含一个头文件即可使用该封装器。
背景
几个月前,我在 CodeProject 上发表了第一篇文章 一个简单的 Windows HTTP 封装器,使用 C++ 开发。在过去的几个月里,我不断更新它,最终得到了基于 C++ 中 WinHTTP API 的全功能 Windows HTTP 封装器。
特点
- 支持 Cookie
- 支持代理
- 支持 GET和POST方法
- 支持自定义请求头
- 支持禁用自动重定向
- 支持 HTTPS
- 支持接收进度
- 其他一些特性
Using the Code
类图如下:
 
 
您可以从函数名称中理解大多数函数的功能。请参考示例部分了解一些典型示例。
示例
简单的 Get 请求
Get 请求是最常见的请求。浏览网页会导致一个或多个 Get 请求。
// Set URL.
WinHttpClient client(L"https://codeproject.org.cn/");
 
// Send HTTP request, a GET request by default.
client.SendHttpRequest();
 
// The response header.
wstring httpResponseHeader = client.GetResponseHeader();
 
// The response content.
wstring httpResponseContent = client.GetResponseContent();
简单的 Post 请求
Post 请求通常发生在登录或发布帖子时。
WinHttpClient client(L"https://codeproject.org.cn/");
 
// Set post data.
string data = "title=A_NEW_THREAD&content=This_is_a_new_thread.";
client.SetAdditionalDataToSend((BYTE *)data.c_str(), data.size());
 
// Set request headers.
wchar_t szSize[50] = L"";
swprintf_s(szSize, L"%d", data.size());
wstring headers = L"Content-Length: ";
headers += szSize;
headers += L"\r\nContent-Type: application/x-www-form-urlencoded\r\n";
client.SetAdditionalRequestHeaders(headers);
 
// Send HTTP post request.
client.SendHttpRequest(L"POST");
 
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
获取请求的进度
您可以指定一个回调函数来获取请求的进度。
// Progress - finished percentage.
bool ProgressProc(double progress)
{
    wprintf(L"Current progress: %-.1f%%\r\n", progress);
    return true;
}
 
void ProgressTest(void)
{
    // Set URL and call back function.
    WinHttpClient client(L"https://codeproject.org.cn/", ProgressProc);
    client.SendHttpRequest();
    wstring httpResponseHeader = client.GetResponseHeader();
    wstring httpResponseContent = client.GetResponseContent();
}
指定用户代理
用户代理是一个 string,客户端使用它来向 Web 服务器标识自己,以便服务器可以知道您使用的客户端软件,例如 Internet Explorer 8、Chrome 或 FireFox。您可以指定用户代理来伪装成 Internet Explorer 8,从而欺骗 Web 服务器,因为有时服务器仅支持 Internet Explorer 8。
WinHttpClient client(L"https://codeproject.org.cn/");
 
// Set the user agent to the same as Internet Explorer 8.
client.SetUserAgent(L"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1;...)");
 
client.SendHttpRequest();
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
指定代理
有时,我们必须通过代理连接到 Web。默认情况下,WinHttpClient 直接连接到 Web 服务器,如果连接失败,则使用 Internet Explorer 设置进行连接。您也可以通过调用函数 SetProxy 来指定代理。
WinHttpClient client(L"https://codeproject.org.cn/");
 
// Set the proxy to 192.168.0.1 with port 8080.
client.SetProxy(L"192.168.0.1:8080");
 
client.SendHttpRequest();
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
处理 Cookies
Cookie(也称为跟踪 Cookie、浏览器 Cookie 和 HTTP Cookie)是由 Web 浏览器存储在用户计算机上的一个小文本片段。Cookie 由包含信息位的一个或多个名称-值对组成。
Cookie 由 Web 服务器作为 HTTP 标头发送到 Web 浏览器,然后每次浏览器访问该服务器时,都会将 Cookie 不变地发送回服务器。Cookie 可用于身份验证、会话跟踪(状态维护)、存储站点首选项、购物车内容、基于服务器的会话的标识符,或可以通过存储文本数据实现的任何其他操作 (http://en.wikipedia.org/wiki/HTTP_cookie)。
您可以通过调用 SetAdditionalRequestCookies 来指定要发送的 Cookie,并通过调用 GetResponseCookies 来获取响应 Cookie。
WinHttpClient client(L"https://codeproject.org.cn/");
 
// Set the cookies to send.
client.SetAdditionalRequestCookies(L"username=jack");
 
client.SendHttpRequest();
 
// Get the response cookies.
wstring httpResponseCookies = client.GetResponseCookies();
 
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
HTTPS
WinHttpClient client(L"https://www.google.com/");
// Accept any certificate while performing HTTPS request.
client.RequireValidSslCertificates(false);
client.SendHttpRequest();
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
多个请求
WinHttpClient client(L"http://www.google.com/");
 
client.SendHttpRequest();
wstring httpResponseHeader = client.GetResponseHeader();
wstring httpResponseContent = client.GetResponseContent();
// Update the URL.
client.UpdateUrl(L"http://www.microsoft.com/");
client.SendHttpRequest();
httpResponseHeader = client.GetResponseHeader();
httpResponseContent = client.GetResponseContent();
一个完整的示例
Codeproject.com 需要登录才能下载文件。此示例登录,获取 Cookie,请求我的第一篇 CodeProject 文章 一个简单的 Windows HTTP 封装器,使用 C++ 开发 的源代码 (win_HTTP_wrapper/WinHttpClient_Src.zip),然后将文件保存到硬盘。此示例包括 Cookie 处理、Post 请求、请求头自定义等。
// 1. Get the initial cookie.
WinHttpClient getClient
	(L"https://codeproject.org.cn/script/Membership/LogOn.aspx");
getClient.SetAdditionalRequestHeaders
	(L"Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, ...");
if (!getClient.SendHttpRequest())
{
    return;
}
 
// 2. Post data to get the authentication cookie.
WinHttpClient postClient
	(L"https://codeproject.org.cn/script/Membership/LogOn.aspx?rp=
	%2fscript%2fMembership%2fLogOn.aspx");
 
// Post data.
wstring username = L"YourCodeProjectUsername";
wstring password = L"YourPassword";
postClient.SetAdditionalRequestCookies(getClient.GetResponseCookies());
string data = "FormName=MenuBarForm&Email=";
data += (char *)_bstr_t(username.c_str());
data += "&Password=";
data += (char *)_bstr_t(password.c_str());
data += "&RememberMeCheck=1";
postClient.SetAdditionalDataToSend((BYTE *)data.c_str(), data.size());
 
// Post headers.
wstring headers = L"...Content-Length: %d\r\nProxy-Connection: 
		Keep-Alive\r\nPragma: no-cache\r\n";
wchar_t szHeaders[MAX_PATH * 10] = L"";
swprintf_s(szHeaders, MAX_PATH * 10, headers.c_str(), data.size());
postClient.SetAdditionalRequestHeaders(szHeaders);
if (!postClient.SendHttpRequest(L"POST", true))
{
    return;
}
 
// 3. Finally get the zip file.    
WinHttpClient downloadClient(L"win_HTTP_wrapper/WinHttpClient_Src.zip");
downloadClient.SetUserAgent(L"Mozilla/4.0 
		(compatible; MSIE 8.0; Windows NT 5.1; ...)");
 
// Sending this cookie makes the server believe you have already logged in.
downloadClient.SetAdditionalRequestCookies(postClient.GetResponseCookies());
if (!downloadClient.SendHttpRequest())
{
    return;
}
downloadClient.SaveResponseToFile(L"C:\\WinHttpClient_Src.zip");
关注点
- 有时,先让一段新代码运行起来,然后再改进它,是个好主意。
- 阅读超文本传输协议 (RFC 2616) 将有很大帮助。
- 使用 HTTP 监控工具来帮助开发,例如 HTTPAnalyzer或HTTPWatch。
- 使用类 _bstr_t在wchar_t*和char*之间进行转换非常快速且容易。
历史
- 2010-9-21 2 项增强功能,感谢 Scott Leckie
- 2010-4-29 修复了 2 个错误,感谢 Wong Shao Voon
- 2009-9 全功能版本
- 2008-7 初始版本




