yii2 ajax提交报400错误“csrf token missing or incorrect”主因是前端未正确传递动态csrf令牌:需确保页面注入meta标签、每次请求实时读取token、统一通过x-csrf-token头发送,多应用需匹配csrfparam配置,前后端分离应由接口返回token并内存暂存校验。

Yii2 表单提交报 400 错误、提示“CSRF token missing or incorrect”,绝大多数情况是 AJAX 请求没带对 CSRF 令牌——不是后端没生成,而是前端没传准、没传新、或传错位置。
确认页面是否已正确注入 CSRF 元信息
Yii2 默认会在 中输出两个关键 meta 标签:
-
<meta name="csrf-param" content="_csrf-backend">(参数名,需与配置一致) -
<meta name="csrf-token" content="abc123...xyz">(当前有效令牌值)
检查网页源码,确保这两个标签存在且内容非空。如果用的是多应用(如 frontend/backend),name="csrf-param" 的值必须和 config/web.php 中 request 组件的 csrfParam 完全一致,例如:'csrfParam' => '_csrf-backend',那隐藏域或 header 就必须用 _csrf-backend 作键名,不能写成 _csrf。
AJAX 请求必须动态读取 meta,不能硬编码或缓存
下面这种写法是典型错误:
<script> $.<a style="color:#f60; text-decoration:underline;" title= "ajax"href="https://m.php.cn/zt/15849.html" target="_blank">ajaxSetup({ headers: { 'X-CSRF-Token': '<?= Yii::$app->request->csrfToken ?>' } }); </script>原因:PHP 渲染时生成一次 token,但 Yii2 的 token 是「每次使用即轮换」的,AJAX 发起时若仍用页面加载时的旧值,就会失败。
正确做法是每次请求前实时读取 meta 标签:
- 用 jQuery:
var token = $('meta[name="csrf-token"]').attr('content'); - 用原生 JS:
document.querySelector('meta[name="csrf-token"]').getAttribute('content') - 然后在 AJAX 中显式带上:
headers: { 'X-CSRF-Token': token }或data: { '_csrf-backend': token }
表单 enctype 或 JS 拦截时别漏掉 _csrf 字段
以下场景容易丢 token:
- 表单设了
enctype="multipart/form-data",但用 JS 拦截后只 append 文件字段,忘了把_csrf-backend也加进 FormData - 用 Vue/React 等框架绑定表单,把
_csrf-backend当普通字段但未设为响应式,提交时值为空字符串 - Pjax 刷新后,表单里的 hidden input 没更新(Pjax 不重载
,需在pjax:success回调中手动刷新 hidden 域的 value)
建议统一走 header 方式(X-CSRF-Token),比塞进 body 更稳定,也避免 multipart 场景下字段遗漏。
前后端分离项目请改用接口返回 token
如果前端是独立域名或 SPA 应用,依赖 cookie 同步 token 风险高(跨域、SameSite 限制、缓存失效)。更可靠的做法是:
- 登录或首次请求时,后端在响应体中返回
"csrf_token": "xxx" - 前端将该值暂存在内存(
let currentCsrf = 'xxx'),不存 localStorage - 所有 POST/PUT/DELETE 请求都通过 header
X-CSRF-Token: xxx提交 - 后端在 action 中显式校验:
if (!Yii::$app->request->validateCsrfToken()) { throw new BadRequestHttpException(); }
这样既绕过 cookie 限制,又避免因页面缓存导致 token 失效问题。











