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

Laravel会话过期时,如何在客户端无刷新处理TokenMismatchException?

解决Laravel+Ajax中会话过期导致的TokenMismatchException问题

我完全懂这种 frustration!会话过期后用户操作触发 TokenMismatchException 真的很影响体验,下面给你几个不用离开页面就能刷新 CSRF Token 的靠谱方案:

方案一:定时自动刷新前端CSRF Token

Laravel 默认会在页面的 <meta> 标签里注入 CSRF Token,我们可以定时从后端获取最新的 Token,更新前端存储的值,从根源上避免使用过期 Token 发起请求。

步骤1:添加后端刷新Token接口

在 routes/api.php 中添加一个GET接口(GET请求默认不受CSRF保护,适合仅获取Token的场景):

Route::get('/refresh-csrf-token', function () {
    return response()->json([
        'csrf_token' => csrf_token()
    ]);
});

步骤2:前端定时更新Token

修改你的前端代码,用 setInterval 定时请求接口更新Token,同时更新axios的默认请求头(axios会自动读取这个头作为CSRF Token):

// 初始化时先设置一次Token
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

// 每30分钟刷新一次Token(可以根据你的session生命周期调整,比如设为session过期时间的80%)
setInterval(() => {
    axios.get('/api/refresh-csrf-token')
        .then(response => {
            const newToken = response.data.csrf_token;
            // 更新页面meta标签的Token
            document.querySelector('meta[name="csrf-token"]').setAttribute('content', newToken);
            // 更新axios默认请求头的Token
            axios.defaults.headers.common['X-CSRF-TOKEN'] = newToken;
        })
        .catch(error => {
            console.error('刷新CSRF Token失败:', error);
        });
}, 30 * 60 * 1000);

这样你的请求就不用手动在FormData里append _token了,axios会自动带上X-CSRF-TOKEN头,Laravel会识别这个头作为CSRF Token。

方案二:捕获Token过期错误后自动重试请求

如果定时刷新不是你的首选,也可以在请求失败时捕获TokenMismatchException,刷新Token后自动重试原请求,这种方式更高效,只在需要时更新Token。

步骤1:完善后端异常返回

保持你现有的异常处理代码,但改用更标准的419状态码(Laravel默认对TokenMismatch返回419),同时明确错误标识:

// 在app/Exceptions/Handler.php的render方法中
if ($exception instanceof \Illuminate\Session\TokenMismatchException) {
    if ($request->ajax()) {
        return response()->json([
            'error' => [
                'code' => 'TOKEN_EXPIRED',
                'message' => 'CSRF Token已过期,请重试'
            ]
        ], 419);
    }
}

步骤2:添加axios响应拦截器处理重试

在axios初始化时添加响应拦截器,捕获419错误,刷新Token后重试原请求:

// 创建axios实例(推荐用实例而非全局axios,避免冲突)
const api = axios.create({
    baseURL: '/'
});

// 响应拦截器
api.interceptors.response.use(
    response => response,
    async error => {
        const originalRequest = error.config;
        // 判断是否是Token过期错误,且还没重试过
        if (error.response.status === 419 && !originalRequest._retry) {
            originalRequest._retry = true;
            
            // 请求新的Token
            const tokenResponse = await api.get('/api/refresh-csrf-token');
            const newToken = tokenResponse.data.csrf_token;
            
            // 更新页面meta标签和axios头
            document.querySelector('meta[name="csrf-token"]').setAttribute('content', newToken);
            api.defaults.headers.common['X-CSRF-TOKEN'] = newToken;
            
            // 更新原请求中的Token(如果是FormData格式)
            if (originalRequest.data instanceof FormData) {
                originalRequest.data.set('_token', newToken);
            }
            
            // 重试原请求
            return api(originalRequest);
        }
        return Promise.reject(error);
    }
);

// 用这个api实例发起登录请求
api.post('/sign-in', form_data )
.then(function(resp){
    console.log(resp.data.data);
})
.catch(function(error){
    printErrorMsg(error.response.data.error.message);
});

方案三:辅助优化:延长会话生命周期(可选)

如果你的业务场景允许,可以适当延长session的过期时间,在 config/session.php 中修改:

'lifetime' => env('SESSION_LIFETIME', 240), // 把默认的120分钟改成更大的值,比如240
'expire_on_close' => false,

不过这只是缓解手段,不能完全避免Token过期问题,还是要结合前面的主动刷新或重试方案。


内容的提问来源于stack exchange,提问作者Emeka Emmanuel Oziri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:43:30