You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:42:56