令牌错误主因是token未正确生成、未提交或session异常;需确保模板用{:token()}渲染、session正常启动、避免误用csrf_token(),并注意ajax需手动传递token。

为什么 token 验证总提示“令牌错误”?
ThinkPHP5 的表单令牌验证失败,绝大多数情况不是框架 bug,而是 token 未正确生成、未随表单提交,或 session 未正常工作。核心在于:表单页面必须调用 csrf_token()(或 token())生成并渲染隐藏域,且该 token 必须与当前 session 中存储的值一致。
常见现象包括:Token error、非法请求、提交后直接跳转到错误页但无明确日志;尤其在 Nginx + PHP-FPM 环境、多服务器部署、或使用了自定义 session 驱动时更易触发。
- 检查模板中是否真有
{:token()}或<?php echo token(); ?>—— 漏写或写成{:csrf_token()}(TP5 不识别这个)会直接导致无 token 提交 - 确认 session 已启动:控制器方法执行前,
session_start()必须成功(可通过var_dump(session_id())验证) - 若用了 Redis 或 Memcached 存 session,请确认连接正常,且 key 前缀/序列化方式未导致读取失败
- 浏览器禁用 cookie 或跨域请求(如前端用 Vue 发起 POST 到 TP5 接口)时,session_id 无法回传,token 必然不匹配
token() 和 csrf_token() 到底该用哪个?
ThinkPHP5.0/5.1 中只有 token() 是内置函数,用于生成和校验表单令牌;csrf_token() 是 Laravel 风格写法,在 TP5 中不存在,调用会报 Call to undefined function csrf_token() 错误。
正确用法分两步:
- 在模板中插入:
{:token()}(模板引擎语法)或<?php echo token(); ?>(PHP 原生写法),它会输出类似<input type="hidden" name="__token__" value="abc123..."> - 控制器中无需手动调用验证函数——只要在控制器类顶部加
protected $middleware = ['think\middleware\TokenCheck'];,或全局注册中间件,TP5 就会在 POST 请求时自动校验__token__字段 - 若需手动控制,可用
\think\Request::instance()->checkToken(),返回布尔值;注意该方法默认校验__token__字段,不可改名
POST 提交后 token 失效?可能是 session 生命周期问题
TP5 默认将 token 存在 session 中,并设置为「一次性有效」:校验成功后立即从 session 删除。这意味着同一 token 不能重复提交,也意味着如果用户打开表单页后长时间不提交,session 过期会导致 token 失效。
关键参数在 config/app.php 中:
-
'token_on' => true:开启令牌验证(必须为 true) -
'token_name' => '__token__':字段名,前后端必须一致,不可随意修改 -
'token_reset' => true:设为 false 可让 token 多次有效(不推荐,仅调试用) - session 过期时间由
session.expire控制,默认 3600 秒;若表单复杂、用户填写慢,建议适当延长 - 若用 CLI 或队列触发页面生成(如导出页预生成),session 可能未初始化,此时
token()返回空字符串
Ajax 提交怎么带 token?别漏掉 header 和 data
Ajax 场景下,token() 仍需在页面加载时渲染出来,但不能只靠隐藏域自动提交——jQuery 或 axios 默认不会把表单隐藏域塞进请求体,得手动处理。
两种可靠做法:
- 从 DOM 读取:
const token = $('input[name="__token__"]').val();,然后在 data 中带上:data: { ...otherData, '__token__': token } - 或统一加 header(需后端配合):
headers: { 'X-CSRF-TOKEN': $('input[name="__token__"]').val() },但 TP5 默认不从 header 读 token,必须在中间件里自行扩展读取逻辑 - 切记不要在 Ajax 请求中重复调用
token()函数生成新值——那会覆盖 session 里的原始 token,导致校验失败 - 如果用了 Vue/React 单页应用,token 应在服务端渲染初始 HTML 时注入(如挂载到
window.__TOKEN__),而不是在组件里调用 PHP 函数
最常被忽略的一点:token 校验依赖 session 的完整性,而 session 又高度依赖客户端 cookie 和服务端存储的一致性。任何一环断开(比如 Nginx 配置了 proxy_cookie_path 却没匹配路径、CDN 缓存了带 Set-Cookie 的响应、或 PHP 的 session.use_cookies=Off),都会让 token 看似“随机失败”。先盯住 session,再查 token。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











