Chrome扩展动态切换带认证代理时onAuthRequired循环认证问题
动态切换带认证代理后Chrome扩展出现凭据交替、认证循环失败问题
我开发了一款能动态切换带用户名/密码认证代理的Chrome扩展,使用chrome.proxy.settings修改代理配置,同时监听webRequest.onAuthRequired事件,在服务器要求认证时传递从代理URL解析出的账号密码。核心代码如下:
async function setProxy(proxy) { proxy = new URL(proxy) var config = { mode: 'fixed_servers', rules: { singleProxy: { scheme: "http", host: proxy.hostname, port: parseInt(proxy.port), }, bypassList: ["localhost"], } } chrome.proxy.settings.set( { value: config, scope: "regular", }, function () { } ) var myCredetails = { username: proxy.username, password: proxy.password } chrome.webRequest.onAuthRequired.addListener( function (details, callbackFn) { console.log(myCredetails) console.log("onAuthRequired!", details, callbackFn); callbackFn({ authCredentials: myCredetails }); }, { urls: ["<all_urls>"] }, ['asyncBlocking'] ); }
问题现象
首次设置代理时认证正常,但切换到其他代理后,代理配置虽然更新了,webRequest.onAuthRequired触发时会交替使用新旧代理的凭据(比如旧的{username: '11111', password: '11111'}和新的{username: '22222', password: '22222'}交替出现在日志里),最终导致认证循环失败。
问题根源
每次调用setProxy函数时,都会新增一个webRequest.onAuthRequired的监听器,但从来没有移除过旧的监听器。当代理认证事件触发时,所有已添加的监听器都会被执行,它们分别返回各自保存的新旧凭据,浏览器收到不同的认证信息后就会陷入重试循环。
你看到的"用Promise而非回调处理认证"是优化方向,但不是当前循环问题的直接原因。
解决方案
- 每次添加新监听器前移除旧的监听器:用变量保存监听器引用,切换代理时先移除之前的监听器,再添加新的。
- 异步操作规范化:把
chrome.proxy.settings.set封装为Promise,确保代理配置更新完成后再处理监听器逻辑。 - 优化认证回调写法:使用
async/await配合Promise处理认证逻辑,符合现代JS写法。
修正后的代码示例:
// 保存监听器引用,用于后续移除 let authListener = null; // 封装chrome.proxy.settings.set为Promise function setProxyConfig(config) { return new Promise((resolve) => { chrome.proxy.settings.set({ value: config, scope: "regular" }, resolve); }); } async function setProxy(proxy) { const proxyUrl = new URL(proxy); const config = { mode: 'fixed_servers', rules: { singleProxy: { scheme: "http", host: proxyUrl.hostname, port: parseInt(proxyUrl.port), }, bypassList: ["localhost"], } }; // 先移除旧的监听器(如果存在) if (authListener) { chrome.webRequest.onAuthRequired.removeListener(authListener); authListener = null; } // 等待代理配置更新完成 await setProxyConfig(config); const credentials = { username: proxyUrl.username, password: proxyUrl.password }; // 创建新的监听器并保存引用 authListener = async (details) => { console.log("onAuthRequired!", details); console.log("Using credentials:", credentials); // 返回认证凭据(asyncBlocking模式下支持返回Promise) return { authCredentials: credentials }; }; // 添加新的监听器 chrome.webRequest.onAuthRequired.addListener( authListener, { urls: ["<all_urls>"] }, ['asyncBlocking'] ); }
额外说明
- 使用
async函数作为监听器时,Chrome会自动处理Promise的返回值,不需要手动调用callbackFn,这也是"用Promise处理认证"的正确用法。 - 必须确保每次切换代理时移除旧监听器,避免多个监听器同时响应认证事件。
内容的提问来源于stack exchange,提问作者Данила Кирсанов
相关产品推荐
相关产品推荐

