Laravel 8登录后首次加载页面Ajax请求遇CSRF Token mismatch错误
问题成因与解决方案
成因
- 登录操作会触发Laravel默认的session重新生成机制,若表单页面在登录前被浏览器或服务器端缓存,登录后首次加载的是缓存页面,页面内的CSRF令牌属于登录前的旧session,与当前登录后的新session令牌不匹配,导致请求触发Token mismatch错误。
- 部分场景下,登录后跳转表单页面时,服务器端session的CSRF令牌尚未完成同步,页面渲染时生成的令牌与session存储的令牌不一致;刷新页面后重新渲染,令牌才完成同步,请求恢复正常。
解决方法
1. 禁止表单页面缓存
通过响应头或meta标签禁止浏览器缓存表单页面,确保每次加载都是服务器重新渲染的最新页面:
- 控制器层设置响应头:
return view('your-form-view') ->header('Cache-Control', 'no-cache, no-store, must-revalidate') ->header('Pragma', 'no-cache') ->header('Expires', '0'); - 页面
<head>中添加meta标签:<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Expires" content="0">
2. 登录后使用重定向跳转表单页面
登录成功后,避免直接返回表单视图,改用重定向方式跳转,强制浏览器重新请求页面,确保加载最新的CSRF令牌:
// 登录控制器逻辑 if (Auth::attempt($credentials)) { return redirect()->intended('/form-route'); }
3. 从XSRF-TOKEN Cookie获取令牌
放弃直接使用页面隐藏字段的令牌,改为从浏览器的XSRF-TOKEN Cookie中读取,该Cookie会随登录后的session自动更新:
// 获取Cookie中的XSRF令牌 function getCsrfToken() { const cookieValue = `; ${document.cookie}`; const parts = cookieValue.split(`; XSRF-TOKEN=`); if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift()); } // Ajax请求时使用 $.ajax({ url: '/your-ajax-endpoint', method: 'POST', data: { _token: getCsrfToken(), // 其他请求数据 } });
也可通过设置全局Ajax请求头,Laravel会自动验证X-XSRF-TOKEN头:
$.ajaxSetup({ headers: { 'X-XSRF-TOKEN': getCsrfToken() } });
4. 登录后手动刷新页面CSRF令牌
登录成功后,请求服务器获取新的CSRF令牌,更新页面中的隐藏字段:
- 添加获取令牌的路由:
Route::get('/refresh-csrf', function() { return response()->json(['token' => csrf_token()]); }); - 登录成功后执行更新逻辑:
fetch('/refresh-csrf') .then(res => res.json()) .then(data => { document.querySelector('input[name="_token"]').value = data.token; });
内容的提问来源于stack exchange,提问作者Francesc Roca Rodríguez
相关产品推荐
相关产品推荐

