必须在choose或before回调中动态读取DOM中的CSRF Token,不可写死在data配置里,因token随页面刷新变化且render初始化后data固化,静态设置会导致后续更新无效。
layui upload 上传时如何动态传入 CSRF Token
csrf token 必须在每次上传前从 dom 中实时读取,不能写死在 data 配置里——因为 django/laravel 等框架生成的 token 是随页面刷新变化的,render 初始化后 data 就固化了,后续 token 更新不会生效。
正确做法是在 choose 或 before 回调中动态取值。推荐用 choose,因为它在用户选中文件后立即触发,且能保证 DOM 中的 input[name=csrfmiddlewaretoken] 已渲染完毕(Django)或 input[name=_token](Laravel)。
-
choose里直接读取:data: { csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val() } - 若用 Laravel,改为:
data: { _token: $('input[name=_token]').val() } - 不要依赖
$('#form').serialize(),它可能漏掉隐藏字段或被表单重置干扰 - 如果页面没渲染
{% csrf_token %}(Django)或{!! csrf_field() !!}(Laravel),$('input[name=...]').val()会返回undefined,导致 403;务必确认模板已插入该标签
为什么不能在 upload.render 里静态写 data.csrfmiddlewaretoken
因为 upload.render 执行时,data 对象被浅拷贝进组件内部配置,后续对原始对象的修改(比如页面登录后刷新 token)不会同步过去。即使你 later 手动改 uploadInst.config.data.csrfmiddlewaretoken = newToken,Layui 也不监听 config 变更,上传仍用旧值。
本质是 Layui upload 的设计机制:data 只在初始化和 choose/before 时读取一次,不是响应式绑定。
- 错误写法:
data: { csrfmiddlewaretoken: document.querySelector('input[name=csrfmiddlewaretoken]').value }(执行 render 时就取了一次值) - 正确写法:把取值逻辑放到回调里,确保每次上传都重新读 DOM
- 如果 token 存在 JS 变量里(比如全局
window.CSRF_TOKEN),也要确保该变量在 upload.render 前已赋值,否则取到 undefined
Django 和 Laravel 的 token 字段名与后端校验差异
字段名不统一是 403 的常见原因。Django 默认要求 csrfmiddlewaretoken 字段;Laravel 默认认 _token;而有些自定义中间件可能要求 X-CSRF-TOKEN 放在请求头里——这和 data 传参是两套路径,别混用。
- Django 后端:必须走
data字段传,header 里加X-CSRFToken不起作用(除非你额外写了中间件) - Laravel 后端:默认支持
data里的_token,也支持 header 的X-CSRF-TOKEN(需配合meta[name=csrf-token]) - 若后端要求 header 方式,就得在
before里设:this.headers['X-CSRF-TOKEN'] = $('meta[name=csrf-token]').attr('content') - 检查后端日志或调试器,确认收到的字段名和值是否匹配,比猜更可靠
上传失败时如何快速定位是 CSRF 还是其他问题
403 错误不等于一定是 CSRF 失败。先排除明显干扰项,再聚焦 token 本身。
- 打开浏览器 Network 面板,点击上传请求 → 查看 Payload 标签页:确认
csrfmiddlewaretoken或_token字段是否存在、值是否为空字符串或undefined - 对比 Response Headers:Django 返回
403 Forbidden且 body 提示CSRF verification failed;Laravel 返回419 Page Expired或401 Unauthorized - 临时禁用中间件测试(仅开发环境):Django 注释
VerifyCsrfToken,Laravel 在VerifyCsrfToken.php的$except加接口路径,如果上传成功,基本锁定是 token 问题 - 注意:Django 的
csrf_token有效期为 2 小时,页面长期未操作可能导致 token 过期,此时刷新页面即可,无需改代码











