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

Chrome扩展V3迁移:DeclarativeNetRequest改请求头需重载才生效

Chrome扩展V3迁移:DeclarativeNetRequest规则无法在标签导航后立即生效

问题说明

从Chrome扩展V2迁移到V3时,由于WebRequestBlocking被弃用,改用DeclarativeNetRequest拦截并修改出站请求头。需求是表单提交后,拦截当前标签的所有后续出站请求并添加自定义请求头,但目前遇到的问题是:表单提交后标签会导航到新URL,但请求头无法被自动添加,必须强制重载标签才能让规则生效。

已经尝试过的方案:

  • 用chrome.tabs.onUpdated监听标签更新来应用规则
  • 添加chrome.webNavigation.onBeforeNavigate和chrome.webRequest.onBeforeSendHeaders监听器
    以上方案都没法在不重载标签的情况下让规则生效。

当前使用的background.ts代码:

// Handle submission of new data
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {

const tabId = sender?.tab?.id ?? message.tabId;
const tab = await chrome.tabs.get(tabId!);

switch (message.type) {
    case 'submit':
        const options = await getOptions();
        
        newUrl.searchParams.set('value', message.value);

        // If the new Url would be the same as the old URL, don't update the tab
        if (newUrl.toString() === tab.url) {
            return;
        }
        chrome.tabs.update(tabId, {url: newUrl.toString()}, (r) => {
            console.log('updated tab', r);
        });
        break;
    case 'log':
        console.log(`${message.message}:`, message);
        break;
}
});

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
console.log('On Tab Updated');
if (tab.status !== 'loading') {
    return;
}
// Get the declarative net request rules for this session
const allRules = await chrome.declarativeNetRequest.getSessionRules();

// Get the current rules for this tab
const currentRulesForTab = allRules.filter((rule) => {
    return rule.condition?.tabIds?.includes(tabId);
});

if (
    condition
) {
    const newRulesForTab = await getRules();

    if (!currentRulesForTab.length) { 
        await chrome.tabs.sendMessage(tabId, {
            type: 'log',
            message: 'Initializing session rules for this tab',
            rules: newRulesForTab
        });
        await chrome.declarativeNetRequest.updateSessionRules({
            addRules: newRulesForTab
        });
        // Reload this tab again
        await chrome.tabs.reload(tabId);
    } else { 
        if (currentRules !== newRules) {
            // Send chrome message to this tab to log that the tab is being updated
            await chrome.tabs.sendMessage(tabId, {
                type: 'log',
                message: 'Updating session rules for this tab',
                rules: newRulesForTab
            });
            await chrome.declarativeNetRequest.updateSessionRules({
                removeRuleIds: currentRulesForTab.map((rule) => rule.id),
                addRules: newRulesForTab
            });
            // Reload this tab again
            await chrome.tabs.reload(tabId);
        }
    }
} else { 
    if (currentRulesForTab.length) {
        // Send chrome message to this tab to log that the tab is being updated
        await chrome.tabs.sendMessage(tabId, {
            type: 'log',
            message: 'Removing session rules for this tab',
            rules: currentRulesForTab
        });
        await chrome.declarativeNetRequest.updateSessionRules({
            removeRuleIds: currentRulesForTab.map((rule) => rule.id)
        });
        // Reload this tab again
        await chrome.tabs.reload(tabId);
    }
}
});

问题根源

DeclarativeNetRequest的会话规则(session rules)在标签导航的当前导航周期内不会立即生效——因为发起导航请求时,规则还没被添加或更新,所以这个导航请求以及后续的请求都不会匹配到新规则,必须重载标签开启新的导航周期才能触发规则。

解决方法

方法一:表单提交时提前配置规则,再触发导航

不要等标签更新后才加规则,而是在调用chrome.tabs.update导航之前,先把规则配置好,这样导航请求本身就能被规则匹配到。

修改后的代码:

// Handle submission of new data
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  const tabId = sender?.tab?.id ?? message.tabId;
  const tab = await chrome.tabs.get(tabId!);

  switch (message.type) {
    case 'submit':
      const options = await getOptions();
      // 补充newUrl的初始化(原代码中缺失)
      const newUrl = new URL(tab.url!);
      newUrl.searchParams.set('value', message.value);

      if (newUrl.toString() === tab.url) {
        return;
      }

      // 第一步:提前更新会话规则
      const allRules = await chrome.declarativeNetRequest.getSessionRules();
      const currentRulesForTab = allRules.filter(rule => rule.condition?.tabIds?.includes(tabId));
      const newRulesForTab = await getRules();

      // 先移除旧规则(如果存在)
      if (currentRulesForTab.length) {
        await chrome.declarativeNetRequest.updateSessionRules({
          removeRuleIds: currentRulesForTab.map(rule => rule.id)
        });
      }
      // 添加新规则
      await chrome.declarativeNetRequest.updateSessionRules({
        addRules: newRulesForTab
      });

      // 第二步:触发标签导航
      chrome.tabs.update(tabId, { url: newUrl.toString() }, (r) => {
        console.log('updated tab', r);
      });
      break;
    case 'log':
      console.log(`${message.message}:`, message);
      break;
  }
});

// 保留tabs.onUpdated的规则清理逻辑(无需重载标签)
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  if (tab.status !== 'loading') return;

  const allRules = await chrome.declarativeNetRequest.getSessionRules();
  const currentRulesForTab = allRules.filter(rule => rule.condition?.tabIds?.includes(tabId));
  
  // 根据你的condition判断是否需要移除规则
  if (!condition && currentRulesForTab.length) {
    await chrome.declarativeNetRequest.updateSessionRules({
      removeRuleIds: currentRulesForTab.map(rule => rule.id)
    });
  }
});

方法二:用webNavigation.onBeforeNavigate提前注入规则

如果没法在表单提交时提前处理,可以监听onBeforeNavigate事件——这个事件发生在导航请求发送之前,此时添加规则能确保请求发出前规则已经生效。

修改后的代码:

// 监听导航前事件,提前注入规则
chrome.webNavigation.onBeforeNavigate.addListener(async (details) => {
  const tabId = details.tabId;
  // 根据目标URL或其他条件判断是否需要应用规则
  if (details.url.includes('你的目标URL匹配规则')) {
    const allRules = await chrome.declarativeNetRequest.getSessionRules();
    const currentRulesForTab = allRules.filter(rule => rule.condition?.tabIds?.includes(tabId));
    const newRulesForTab = await getRules();

    // 没有规则则添加,规则有变化则更新
    if (!currentRulesForTab.length) {
      await chrome.declarativeNetRequest.updateSessionRules({
        addRules: newRulesForTab
      });
    } else if (JSON.stringify(currentRulesForTab) !== JSON.stringify(newRulesForTab)) {
      await chrome.declarativeNetRequest.updateSessionRules({
        removeRuleIds: currentRulesForTab.map(rule => rule.id),
        addRules: newRulesForTab
      });
    }
  }
});

// 原有的消息监听逻辑保持不变,移除导航后的重载操作
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  const tabId = sender?.tab?.id ?? message.tabId;
  const tab = await chrome.tabs.get(tabId!);

  switch (message.type) {
    case 'submit':
      const options = await getOptions();
      const newUrl = new URL(tab.url!);
      newUrl.searchParams.set('value', message.value);

      if (newUrl.toString() === tab.url) {
        return;
      }
      chrome.tabs.update(tabId, { url: newUrl.toString() }, (r) => {
        console.log('updated tab', r);
      });
      break;
    case 'log':
      console.log(`${message.message}:`, message);
      break;
  }
});

注意事项

  • 确保规则的condition里正确设置tabIds,精准绑定目标标签,避免影响其他标签的请求
  • 会话规则(session rules)会在浏览器关闭后自动失效,不需要手动持久化
  • 尽量避免频繁更新规则,可以通过对比规则内容判断是否需要更新,减少性能开销

内容的提问来源于stack exchange,提问作者Shresth Bhimrajka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:44:55