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

Chrome扩展MV3点击Zip链接跳转异常,求修正至MV2效果

Chrome扩展MV3实现Zip链接直接跳转的修复方案

问题背景

MV2版本的扩展可在用户点击Zip文件链接时直接跳转到扩展内的web/main.html页面;但MV3版本首次点击会弹出“另存为”对话框,再次点击同一链接才会触发跳转,其他Zip文件也存在相同问题。


原MV2代码实现

manifest.json

{  
  "name": "Test app mv2",  
  "version": "0.1",  
  "manifest_version": 2,  
  "description": "test mv2",  
  "background": {    
    "scripts": [      
      "background.js"    
    ]  
  },  
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",  
  "icons": {    
    "128": "128.png"  
  },  
  "permissions": [    
    "webRequest",    
    "webRequestBlocking",    
    "<all_urls>"  
  ],    
  "web_accessible_resources": [    
    "web/main.html"  
  ]
}

background.js

function getHeaderFromHeaders(headers, headerName) {  
  for (var i=0; i<headers.length; ++i) {    
    var header = headers[i];    
    if (header.name.toLowerCase() === headerName) {      
      return header;    
    }  
  }
}

function isAllowed(details) {  
  var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');    
  if (header) {    
    var headerValue = header.value.toLowerCase().split(';',1)[0].trim();
    var mimeTypes = [      
      'application/zip'    
    ];    
    return (mimeTypes.indexOf(headerValue) !== -1);  
  }
}

chrome.webRequest.onHeadersReceived.addListener(  
  function(details) {    
    if (details.method !== 'GET') {      
      return;    
    }    
    if (!isAllowed(details)) {      
      return;    
    }
    return { redirectUrl: chrome.runtime.getURL('web/main.html') };  
  },  
  {    
    urls: [      
      "<all_urls>"    
    ],    
    types: ['main_frame', 'sub_frame']  
  },  
  ['blocking','responseHeaders'] 
);

原MV3代码实现(存在问题)

manifest.json

{  
  "name": "Test app mv3",  
  "manifest_version": 3,  
  "version": "0.1",  
  "background": {    
    "service_worker": "./background.js"  
  },  
  "action": {      
    "default_title": "SW3"  
  },  
  "host_permissions": [    
    "<all_urls>"  
  ],  
  "permissions": [    
    "webRequest",    
    "declarativeNetRequest",    
    "declarativeNetRequestFeedback",    
    "declarativeNetRequestWithHostAccess"  
  ],    
  "web_accessible_resources": [{    
    "resources": ["web/main.html"],    
    "matches": ["<all_urls>"]  
  }],  
  "content_security_policy": {    
    "extension_pages": "script-src 'self'; object-src 'self'"  
  }
}

background.js

function getHeaderFromHeaders(headers, headerName) {  
  for (var i=0; i<headers.length; ++i) {    
    var header = headers[i];    
    if (header.name.toLowerCase() === headerName) {      
      return header;    
    }  
  }
}

function isAllowed(details) {  
  var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');    
  if (header) {    
    var headerValue = header.value.toLowerCase().split(';',1)[0].trim();
    var mimeTypes = [      
      'application/zip'    
    ];    
    return (mimeTypes.indexOf(headerValue) !== -1);  
  }
}

chrome.webRequest.onHeadersReceived.addListener(  
  function(details) {    
    if (details.method !== 'GET') {      
      return;    
    }    
    if (!isAllowed(details)) {      
      return;    
    }
    chrome.declarativeNetRequest.updateSessionRules({      
      addRules: [{        
        'id': 2001,        
        'priority': 1,        
        'action': {          
          'type': 'redirect',          
          'redirect': {            
            url: chrome.runtime.getURL('web/main.html')        
         }        
        },        
        'condition': {          
          'urlFilter': details.url,          
          'resourceTypes': ['main_frame']        
        }      
      }],    
    removeRuleIds: [2001]    
    });    
    return { redirectUrl: chrome.runtime.getURL('web/main.html') };  
  },  
  {    
    urls: [      
      "<all_urls>"    
    ],    
    types: ['main_frame', 'sub_frame']  
  },  
  ['responseHeaders'] 
);

修复后的MV3代码

1. 修改manifest.json

添加webRequestBlocking权限,移除无需使用的declarativeNetRequest相关权限:

{  
  "name": "Test app mv3",  
  "manifest_version": 3,  
  "version": "0.1",  
  "background": {    
    "service_worker": "./background.js"  
  },  
  "action": {      
    "default_title": "SW3"  
  },  
  "host_permissions": [    
    "<all_urls>"  
  ],  
  "permissions": [    
    "webRequest",    
    "webRequestBlocking"  
  ],    
  "web_accessible_resources": [{    
    "resources": ["web/main.html"],    
    "matches": ["<all_urls>"]  
  }],  
  "content_security_policy": {    
    "extension_pages": "script-src 'self'; object-src 'self'"  
  }
}

2. 修改background.js

移除declarativeNetRequest相关代码,在onHeadersReceived监听参数中添加'blocking':

function getHeaderFromHeaders(headers, headerName) {  
  for (var i=0; i<headers.length; ++i) {    
    var header = headers[i];    
    if (header.name.toLowerCase() === headerName) {      
      return header;    
    }  
  }
}

function isAllowed(details) {  
  var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');    
  if (header) {    
    var headerValue = header.value.toLowerCase().split(';',1)[0].trim();
    var mimeTypes = [      
      'application/zip'    
    ];    
    return (mimeTypes.indexOf(headerValue) !== -1);  
  }
}

chrome.webRequest.onHeadersReceived.addListener(  
  function(details) {    
    if (details.method !== 'GET') {      
      return;    
    }    
    if (!isAllowed(details)) {      
      return;    
    }
    return { redirectUrl: chrome.runtime.getURL('web/main.html') };  
  },  
  {    
    urls: [      
      "<all_urls>"    
    ],    
    types: ['main_frame', 'sub_frame']  
  },  
  ['blocking', 'responseHeaders'] 
);

修复原理

MV3中webRequest.onHeadersReceived监听默认是非阻塞模式,此时返回redirectUrl不会生效,浏览器会触发默认的下载行为。添加webRequestBlocking权限并在监听参数中声明'blocking'后,扩展可在请求处理流程中拦截并修改响应,实现和MV2完全一致的即时跳转效果,无需依赖动态规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 13:03:26