如何捕获C++ MFC Web浏览器发起的GET/POST请求
基于MFC CHTMLView的浏览器:捕获请求/响应 + 来源验证方案
嘿,我正好折腾过基于MFC CHTMLView的浏览器开发,给你梳理几个落地的步骤来实现你要的请求捕获、响应获取和来源验证功能:
一、捕获GET/POST请求
CHTMLView本身没提供直接的请求拦截接口,咱们得靠DWebBrowserEvents2的事件监听来搞定——这是最省心的方案,能在请求发起前就拿到关键信息:
1. 给视图类加事件映射
在你的CHTMLView派生类里,添加上BeforeNavigate2的事件映射,这个事件会在每次导航(不管是页面跳转还是按钮触发的请求)前触发:
BEGIN_EVENTSINK_MAP(CMyHtmlView, CHTMLView) ON_EVENT(CMyHtmlView, AFX_IDW_PANE_FIRST, 250 /* BeforeNavigate2 */, OnBeforeNavigate2, VTS_DISPATCH VTS_BSTR VTS_VARIANT VTS_VARIANT VTS_VARIANT VTS_VARIANT VTS_PBOOL) END_EVENTSINK_MAP()
2. 实现请求捕获逻辑
在OnBeforeNavigate2方法里,咱们可以区分GET/POST,还能拿到请求URL和POST数据:
void CMyHtmlView::OnBeforeNavigate2(LPDISPATCH pDisp, LPCTSTR szURL, const VARIANT& Flags, const VARIANT& TargetFrameName, const VARIANT& PostData, const VARIANT& Headers, BOOL* Cancel) { // 先调用基类的默认处理 CHTMLView::OnBeforeNavigate2(pDisp, szURL, Flags, TargetFrameName, PostData, Headers, Cancel); // 判断请求类型:PostData不为空就是POST,否则是GET BOOL isPost = !(PostData.vt == VT_EMPTY || PostData.vt == VT_NULL); CString strMethod = isPost ? _T("POST") : _T("GET"); CString strRequestURL = szURL; // 打印请求信息(你可以改成写入日志或者存到变量里) TRACE(_T("触发请求:%s %s\n"), strMethod, strRequestURL); // 如果是POST,提取请求体内容 if (isPost && PostData.vt == VT_ARRAY | VT_UI1) { SAFEARRAY* pSA = PostData.parray; BYTE* pRawData; SafeArrayAccessData(pSA, (void**)&pRawData); UINT dataLength = pSA->rgsabound[0].cElements; CString strPostContent; strPostContent.Append((LPCTSTR)pRawData, dataLength); TRACE(_T("POST请求体:%s\n"), strPostContent); SafeArrayUnaccessData(pSA); } }
二、捕获响应内容
要拿到页面的响应内容,咱们可以在DocumentComplete事件里操作——这个事件会在页面(或请求)加载完成后触发:
1. 添加DocumentComplete事件映射
继续在事件映射里加一行:
BEGIN_EVENTSINK_MAP(CMyHtmlView, CHTMLView) // 之前的BeforeNavigate2 ON_EVENT(CMyHtmlView, AFX_IDW_PANE_FIRST, 259 /* DocumentComplete */, OnDocumentComplete, VTS_DISPATCH VTS_BSTR) END_EVENTSINK_MAP()
2. 提取响应内容
通过IHTMLDocument2接口获取页面的HTML内容,这就是服务器返回的响应体了:
void CMyHtmlView::OnDocumentComplete(LPDISPATCH pDisp, LPCTSTR szURL) { CHTMLView::OnDocumentComplete(pDisp, szURL); // 获取文档接口 LPDISPATCH pDocDispatch = GetHtmlDocument(); if (!pDocDispatch) return; IHTMLDocument2* pHtmlDoc = nullptr; HRESULT hr = pDocDispatch->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDoc); if (SUCCEEDED(hr)) { IHTMLElement* pBody = nullptr; hr = pHtmlDoc->get_body(&pBody); if (SUCCEEDED(hr) && pBody) { BSTR bstrHtmlContent = nullptr; pBody->get_innerHTML(&bstrHtmlContent); if (bstrHtmlContent) { CString strResponse = bstrHtmlContent; TRACE(_T("响应内容:%s\n"), strResponse); SysFreeString(bstrHtmlContent); } pBody->Release(); } pHtmlDoc->Release(); } pDocDispatch->Release(); }
如果需要更底层的响应头信息,可以实现IHttpNegotiate接口,重写OnResponse方法来获取响应头字段。
三、验证响应来源合法性
要确保响应来自合法来源,咱们可以从两个关键环节入手:
1. 拦截非法请求(事前验证)
在OnBeforeNavigate2里解析请求的URL,提取域名,和你允许的合法域名对比,不合法直接取消导航:
// 示例:只允许来自指定域名的请求 CString strAllowedDomain = _T("support.google.com"); CString strServerName; DWORD serviceType; CString strObject; INTERNET_PORT port; // 用MFC自带的AfxParseURL解析URL if (AfxParseURL(strRequestURL, serviceType, strServerName, strObject, port)) { if (strServerName.CompareNoCase(strAllowedDomain) != 0) { *Cancel = TRUE; // 取消非法请求 AfxMessageBox(_T("警告:请求来自非法来源,已拦截!")); } }
2. 验证响应的合法性(事后验证)
如果是HTTPS请求,可以通过COM接口获取SSL证书信息,验证证书是否合法;另外也可以在DocumentComplete里检查页面的安全状态,或者解析响应头里的Server等字段,确认是否符合合法来源的特征。
额外提醒
- 别忘了COM接口使用后要调用
Release(),不然会内存泄漏! - 如果页面里有AJAX异步请求,
BeforeNavigate2可能捕获不到——这种情况得监听页面里的XMLHttpRequest对象,或者用WinINet钩子来拦截底层请求。
内容的提问来源于stack exchange,提问作者sagar
相关产品推荐
相关产品推荐

