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

Service Worker的fetch事件中无法读取Authorization请求头如何解决

Service Worker读取不到请求Authorization头导致API请求误缓存的解决方法

问题背景

客户端使用封装的getJSON方法发起带Authorization令牌的GET请求到Node.js服务,函数实现如下:

// Do a secured GET API request and return response object
async function getJSON(url) {
    try {
        // Send request
        const res = await fetch(url, {
            headers: { Authorization: localStorage.getItem('token') }
        });

        // If something went wrong
        if (!res.ok) {
            // If token is invalid
            if (res.status === 401) {
                // Logout
                localStorage.removeItem('token');
                location.replace(`/?msg=${dict.get('expired-session')}`);
            }

            // Return an object with error message and status code
            return { error: res.statusText, status: res.status };
        }

        // Else return response object
        else return await res.json();
    } catch (err) {
        // Return an object with error message
        return { error: err.message };
    }
}

接入Service Worker做静态资源缓存时,为了避免缓存带鉴权的API请求,原逻辑计划通过判断请求是否携带Authorization头识别API请求,跳过缓存流程,初始Service Worker代码如下:

// Fetch event
self.addEventListener('fetch', e => e.respondWith(respond(e)));

async function fetchAndCache(req, cache_name) {
    const { url, headers } = req;
    console.log({ url, headers });

    // Fetch request
    const fetch_res = await fetch(req);

    const is_get = req.method === 'GET';
    const is_api = req.headers.Authorization;
    const is_cahing_domain = cache_domains.some(domain => req.url.includes(domain));

    if (is_cahing_domain && is_get && !is_api) {
        // Open cache and save a cloned result
        const cache = await caches.open(cache_name);
        cache.put(req, fetch_res.clone());
    }

    return fetch_res;
}

async function respond(e) {
    if (!use_cache) return fetch(e.request);

    // Try to get response from cache
    const cached_res = await caches.match(e.request);

    // If response is found, return it
    if (cached_res) return cached_res;

    // If request is not found, try to fetch it
    return await fetchAndCache(e.request, 'main');
}

故障表现

运行时控制台打印的headers对象为空,Authorization头判断逻辑始终为false,导致带令牌的API请求被错误写入缓存;但后端实际可以正常收到请求携带的Authorization令牌,缓存条目中也能看到对应请求携带了该头。

根因分析

问题出在Request对象头的读取方式错误:

  • Fetch API规范中,Request.headers是Headers类实例,不是普通JavaScript对象,不能直接通过点语法(req.headers.Authorization)读取头字段值
  • 直接console.log打印Headers实例时,控制台不会枚举展示其内部存储的键值对,因此看起来是空对象,但头数据实际是存在的,所以后端能正常收到令牌

修复方案

使用Headers实例标准的get()方法读取头字段,修正fetchAndCache函数的头读取逻辑即可:

async function fetchAndCache(req, cache_name) {
    const { url } = req;
    // 标准方式读取Authorization头,头名大小写不敏感,不存在时返回null
    const authToken = req.headers.get('Authorization');
    console.log('Request url:', url, 'Has auth token:', !!authToken);

    // Fetch request
    const fetch_res = await fetch(req);

    const is_get = req.method === 'GET';
    // 存在Authorization头则判定为API请求,不缓存
    const is_api = !!authToken;
    // 修正原代码拼写错误:is_cahing_domain -> is_caching_domain
    const is_caching_domain = cache_domains.some(domain => req.url.includes(domain));

    if (is_caching_domain && is_get && !is_api) {
        // Open cache and save a cloned result
        const cache = await caches.open(cache_name);
        cache.put(req, fetch_res.clone());
    }

    return fetch_res;
}

优化建议

  • 可以提前在respond函数中判断API请求,直接走网络逻辑,避免不必要的缓存查询,进一步提升性能
  • 除了判断Authorization头,建议同时结合API路径前缀(比如所有接口都走/api/路径)做过滤,避免跨域场景下受CORS头访问限制导致判断失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:09:18