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

如何通过jQuery的ajaxPreFilter设置Ajax请求头?

问题分析

你的核心问题是异步操作的时序冲突:check_token_expiry里的Token刷新请求是异步执行的,但原Ajax请求不会等待这个异步操作完成就直接发送,导致successCallback里的jqXHR.setRequestHeader执行时,请求已经发出,自然无法修改请求头。另外你的currentRequests变量没有正确存储请求实例,调用currentRequests[options.url].abort()会直接报错。

修复方案

我们需要暂停原请求,等待Token刷新完成后,再带着新Token重新发起请求,同时优化请求管理避免重复刷新:

// 标记是否正在刷新Token,避免重复发起刷新请求
let isRefreshingToken = false;
// 存储等待Token刷新完成后需要重新发起的请求队列
let requestQueue = [];

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    // 跳过刷新Token和登录请求的预处理
    const skipUrls = ['API_URL/api/auth/refresh_token', 'API_URL/api/auth/login'];
    if (skipUrls.includes(options.url)) {
        return;
    }

    const currentToken = localStorage.getItem("api_token");
    const tokenExpiry = localStorage.getItem("api_token_expiry");
    const timeNow = Math.floor(Date.now() / 1000);

    // Token未过期,直接设置请求头
    if (tokenExpiry && tokenExpiry > timeNow) {
        jqXHR.setRequestHeader("X-Api-Token", currentToken);
        return;
    }

    // Token已过期,触发刷新流程
    if (!isRefreshingToken) {
        isRefreshingToken = true;
        $.ajax({
            type: 'POST',
            url: "API_URL/api/auth/refresh_token",
            data: "refresh_token=" + localStorage.getItem("refresh_token")
        }).done(function(data) {
            if (data.status == 'success') {
                // 更新本地Token存储
                localStorage.setItem("api_token", data.token);
                localStorage.setItem("refresh_token", data.refresh_token);
                localStorage.setItem("api_token_expiry", data.token_expiry);
                localStorage.setItem("refresh_token_expiry", data.refresh_token_expiry);
                
                // 给当前请求设置新Token并发送
                jqXHR.setRequestHeader("X-Api-Token", data.token);
                // 批量处理队列中等待的请求
                requestQueue.forEach(({ options, resolve }) => {
                    options.headers = options.headers || {};
                    options.headers["X-Api-Token"] = data.token;
                    resolve($.ajax(options));
                });
            }
        }).fail(function() {
            // 刷新失败,跳转登录页并拒绝所有等待请求
            window.location.href = "login.html";
            requestQueue.forEach(({ reject }) => reject(new Error('Token刷新失败')));
        }).always(function() {
            // 重置刷新状态,清空队列
            isRefreshingToken = false;
            requestQueue = [];
        });
    }

    // 若正在刷新Token,将当前请求加入队列等待处理
    return new Promise((resolve, reject) => {
        requestQueue.push({ options: originalOptions, resolve, reject });
    });
});
关键改进点
  • 异步请求队列:用isRefreshingToken避免重复刷新,requestQueue存储等待请求,刷新完成后统一处理,避免并发冲突。
  • 时序控制:通过Promise让原请求等待Token刷新完成,确保新Token能正确附加到请求头。
  • 错误处理:刷新失败时统一跳转登录页,同时拒绝所有等待的请求,避免无效请求堆积。
  • 直接设置请求头:重新发起请求时直接修改options.headers,确保请求发送时携带最新Token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:57:25