验证码点击不刷新的核心原因是前端未触发新请求或后端缓存干扰:前端需用时间戳(如Date.now())动态更新图片URL防浏览器缓存,后端须确保Session正常、GD扩展启用、输出缓冲清空(ob_clean())、无OPcache/CDN/Nginx缓存拦截,且__captcha__被正确解析为真实路径。

验证码点击后不刷新,核心不是“AI改策略”,而是前端没触发新请求,或后端缓存机制干扰了验证码生成。ThinkPHP 的 Captcha 类依赖 Session 存值,一旦被 OPcache、浏览器、CDN 或服务端输出缓冲(ob)拦截,就会卡在旧图片上。
前端点击必须带唯一参数
图片的 onclick 不能只写 this.src='__captcha__',否则浏览器直接读缓存。必须每次生成不同 URL:
- 用时间戳最稳:
onclick="this.src='/captcha?t='+Date.now()" - 避免 Math.random() 在快速连点时重复(尤其 Safari)
- 检查模板中
__captcha__是否被正确替换成真实路径(如/index/captcha/index),可右键查看网页源码确认
后端要防三类缓存干扰
验证码本质是动态图片响应,任何中间层缓存都会让它“冻住”:
-
OPcache:若开发中改了验证码配置但页面没变,先检查
opcache.validate_timestamps=1,临时加opcache_reset()测试 -
输出缓冲:TP5 常因前置输出(如空格、BOM、echo)导致 header 失效,验证码返回空白。在验证码方法开头加
ob_clean(); -
反向代理:Nginx 的
fastcgi_cache可能缓存了/captcha响应,需在 location 中排除该路径或加fastcgi_cache_bypass 1;
Session 和运行环境必须就绪
验证码值存在 Session 里,生成和校验都靠它。以下任一失败都会导致“不刷新”假象:
立即学习“PHP免费学习笔记(深入)”;
- 确认
session_start()已触发(ThinkPHP6 默认自动,但自定义入口可能漏掉) - 检查
runtime/session目录是否可写(Linux 下常见权限为 755 不够,需 777 或属组正确) - 单独访问验证码 URL(如
/captcha),看是返回图片、空白页,还是 PHP 报错 —— 空白大概率是 GD 库未启用或 ob 问题
别碰验证码类源码,优先用配置解决
网上有教程让你改 Verify.class.php 里的 $reset = false,这属于过时方案(TP6 已不用该类)。现代 ThinkPHP 使用 Captcha 组件,刷新逻辑由前端控制,后端只需保证每次请求都生成新值:
- 确保调用
$captcha->entry()前没有其他输出 - 如需错误后自动刷新,可在表单提交失败时,前端 JS 主动触发一次图片 src 更新
- 不建议用 Redis 替换 Session 存验证码 —— 会破坏框架默认流程,增加校验复杂度



















