C++ 中的异步 HTTP 请求 WinINet 包装器
C++ 的异步 HTTP 下载类

引言
WinINet 使网络编程更加容易,但由于其 C 风格的接口,在 C++ 中使用起来比较困难。因此,我编写了这个代码来对其进行封装。使用它,您可以轻松创建异步 HTTP 请求并接收事件回调。它可以应用于 MFC 和 ATL 项目。
这段代码主要由两个类组成:类 FCHttpRequest
和类 FCHttpRequestManager
。
类 FCHttpRequest
负责实现发送 HTTP 请求和接收响应,它是 WinINet 的一个封装类。
类 FCHttpRequestManager
是 FCHttpRequest
的管理器,负责添加、删除 FCHttpRequest
对象并接收来自 FCHttpRequest
的事件。
与 STL 和 Boost 类似,所有源代码都由 .h 和 .inl 文件组成,您可以轻松地将其集成到您的程序中。
如何使用
- 在您的项目中包含 http_request_manager.h 文件。通常在 stdafx.h 的末尾包含它。
- 创建从类
FCHttpRequestManager
派生的 HTTP 请求管理器类。class CMyManager : public FCHttpRequestManager { //... }; // multiple inheritance attach an exist class class CMyManager : public CDialog, public FCHttpRequestManager { virtual void OnAfterRequestSend (FCHttpRequest& rTask) { // ... } virtual void OnAfterRequestFinish (FCHttpRequest& rTask) { // ... } };
管理器将接收两个事件:
OnAfterRequestSend
和OnAfterRequestFinish
,覆盖您感兴趣的事件。大多数情况下,我们应该覆盖OnAfterRequestFinish
来处理接收到的数据。 - 现在,您可以通过调用
AddRequest
发送 HTTP 请求。
示例
... 下载文件
发送 HTTP 请求
// download whole file
AddDownload (_T("http://phoxo.com/t.zip")) ;
// download file and specifies the starting position
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/t.zip") ;
h.m_start = 30 ; // in byte
AddRequest (h) ;
响应完成事件,处理下载的数据
void OnAfterRequestFinish (FCHttpRequest& rTask)
{
const HTTP_RESPONSE_INFO & r = rTask.GetResponseInfo() ;
bool bOK = false ;
if (r.m_status_code == HTTP_STATUS_OK)
{
if (r.m_content_length)
{
// avoid network broken during downloading
if (r.m_content_length == rTask.GetTotalReceiveByte())
bOK = true ;
}
else
{
// no Content-Type field, maybe is a dynamic page, such as PHP, ASP...
if (r.m_final_read_result)
bOK = true ;
}
}
if (bOK)
{
std::string receive_data ;
rTask.PopReceived (receive_data) ;
// ... process received data
}
}
... 指定 User-Agent
// default User-Agent is same to User-Agent of IE
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_user_agent = _T("My User-Agent") ;
AddRequest (h) ;
... 自定义 HTTP Header
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
// \r\n at end of each line
h.m_header += _T("Referer: http://google.com\r\n") ;
h.m_header += _T("Accept: */*\r\n") ;
h.m_header += _T("x-flash-version: 10,0,0,1\r\n") ;
AddRequest (h) ;
... 指定 Proxy
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_proxy_ip = _T("8.8.8.8") ;
h.m_proxy_port = 8080 ;
AddRequest (h) ;
... 解压缩 GZip HTTP 数据
此功能需要 ZLib 库,您可以从 http://www.zlib.org 获取它。
按以下顺序包含头文件
#include "zlib.h"
#include "http_request_manager.h"
#include "utility/gzip_decompress.h"
在请求头中添加 Accept-Encoding
字段,通知服务器您可以接受 gzip 压缩的数据
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_header += L"Accept-Encoding: gzip, deflate\r\n" ;
AddRequest (h) ;
在完成回调中,您可以使用 gzip_decompress
来解压缩接收到的数据。
void OnAfterRequestFinish (FCHttpRequest& rTask)
{
std::string receive_data ;
rTask.PopReceived (receive_data) ;
if (IsReceiveGZipStream(rTask) && receive_data.size())
{
std::string raw_data ;
if (gzip_decompress (receive_data.c_str(), receive_data.size(), raw_data))
{
receive_data = raw_data ;
}
}
}
... Post multipart/form-data
// this example loads image to memory, then posts to server using multipart/form-data
std::vector buf ;
FCFileEx::Read (_T("c:\\1.jpg"), buf) ;
HTTP_REQUEST_HEADER h (HTTP_REQUEST_HEADER::VERB_TYPE_POST_MULTIPART) ;
h.m_url = _T("http://phoxo.com/") ;
h.AddMultipartFormData ("param1", "value1") ;
h.AddMultipartFormData ("param2", "value2") ;
h.AddMultipartFormData ("pic", &buf[0], buf.size(), "1.jpg") ;
h.EndMultipartFormData() ;
m_task_id = AddRequest (h) ;
... HTTPS
HTTP_REQUEST_HEADER h ;
h.m_url = _T("https://phoxo.com/") ;
// ignores errors that can be caused by the certificate
// host name of the server not matching the host name in the request
h.m_open_flag |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID ;
// ignores errors that can be caused by an expired server certificate
h.m_open_flag |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID ;
AddRequest (h) ;
历史
- 2011 年 8 月 25 日:V2.0
- 重构代码,更多功能,更高效
- 添加了 multipart/form-data POST 支持
- 添加了 HTTPS 支持
- 添加了 GZip 解压缩支持
- 2010 年 1 月 30 日:V1.1
- 重命名为
FCHttpDownload
,从FCHttpDownloadExec
- 修复了在回调中弹出模态对话框时的一个错误
- 修改了
FCHttpRequestManager
的接口 - 从 Internet Explorer 获取默认 User-Agent
- 2009 年 11 月 17 日:初始发布