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

Firefox自定义广告拦截插件中异步阻止请求的实现问题

解决Firefox广告拦截插件中webRequest.filterResponseData与blocking模式的异步冲突问题

问题核心

你当前的矛盾点在于:onBeforeRequest的blocking监听器返回Promise时,浏览器会挂起请求等待Promise决议,但此时请求尚未进入响应阶段,导致filterResponseData无法初始化并触发事件;而不返回Promise的话,无法在响应分析完成后动态决定是否拦截请求。

可行解决思路

1. 拆分拦截逻辑到不同webRequest阶段

将URL预分析和响应分析拆分到两个监听阶段:

  • onBeforeRequest:仅做URL特征匹配,对明确符合拦截规则的请求直接返回{cancel: true}阻止,无需进入响应分析流程。
  • onHeadersReceived:处理需要响应分析的请求,此时服务器已返回响应头,响应流可被正常拦截,适合初始化filterResponseData。

2. 调整响应分析后的拦截方式

响应分析完成后,无需通过返回{cancel: true}阻止请求(此时请求已进入响应阶段),而是通过截断响应流或返回空白内容达到拦截效果。

修改后的代码示例

background.js

// URL预分析:判断是否需要进入响应分析
function preCheckUrl(details) {
    // 替换为你的URL正则检查逻辑
    const shouldAnalyzeResponse = true; // 示例:假设需要分析响应
    if (!shouldAnalyzeResponse) {
        // 直接拦截URL匹配的请求
        return {cancel: true};
    }
    // 无需拦截,继续请求
    return {cancel: false};
}

// 响应分析与处理
async function analyzeResponse(details) {
    let responseChunks = [];
    const filter = browser.webRequest.filterResponseData(details.requestId);
    
    // 收集响应数据块
    filter.ondata = (event) => {
        responseChunks.push(event.data);
    };

    // 等待响应流结束
    await new Promise((resolve) => {
        filter.onstop = resolve;
        filter.onerror = resolve;
    });

    // 合并数据并执行响应特征检查
    const combinedBlob = new Blob(responseChunks);
    const responseText = await combinedBlob.text();
    const shouldBlock = /广告特征正则/.test(responseText); // 替换为你的响应特征正则

    if (shouldBlock) {
        // 截断响应,不给页面返回内容
        filter.disconnect();
    } else {
        // 将收集到的内容重新写入流,保证页面正常加载
        responseChunks.forEach(chunk => filter.write(chunk));
        filter.disconnect();
    }

    return {};
}

// 注册监听器
browser.webRequest.onBeforeRequest.addListener(
    preCheckUrl,
    {urls: blocked_domains},
    ["blocking"]
);

browser.webRequest.onHeadersReceived.addListener(
    analyzeResponse,
    {urls: blocked_domains, types: ["script", "image", "stylesheet", "xmlhttprequest"]}, // 按需指定拦截资源类型
    ["blocking"]
);

关键说明

  • 阶段选择原因:onHeadersReceived是第一个可访问响应流的blocking阶段,此时filterResponseData能正常绑定事件并捕获响应内容,不会出现Promise挂起导致的流初始化失败问题。
  • 响应拦截逻辑:当分析后需要拦截时,调用filter.disconnect()截断响应流,页面无法获取完整内容;若无需拦截,则将收集到的内容重新写入流,保证页面正常加载。
  • 性能优化建议:57000个域名的数组匹配可先做预编译,或使用URL对象提取域名后再匹配,避免数组遍历或正则匹配的性能损耗。

内容的提问来源于stack exchange,提问作者Martynas Jurkėnas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:32:32