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

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而非回调处理认证"是优化方向,但不是当前循环问题的直接原因。


解决方案

  1. 每次添加新监听器前移除旧的监听器:用变量保存监听器引用,切换代理时先移除之前的监听器,再添加新的。
  2. 异步操作规范化:把chrome.proxy.settings.set封装为Promise,确保代理配置更新完成后再处理监听器逻辑。
  3. 优化认证回调写法:使用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,提问作者Данила Кирсанов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:05:09