验证码不显示本质是静态缓存将动态图片接口固化为无效静态内容;需排除路由缓存、添加防缓存头、清理runtime/html下错误缓存文件,并确保session与gd库等底层依赖正常。

静态缓存开启后验证码不显示,本质是缓存机制把本该动态生成的图片“固化”成了静态内容,导致每次请求都返回旧的、无效的或空的响应——验证码接口被缓存了,图像数据就没了。
关闭验证码路由的静态缓存
ThinkPHP 5.1 的静态缓存(如 html 缓存)默认会对所有匹配的 GET 请求生效,包括 /captcha 这类生成图片的接口。必须显式排除:
- 在
application/config.php中找到'html_cache_on'或相关缓存配置,确认已启用后,添加排除规则:'html_cache_exclude' => ['captcha', 'captcha/entry', 'captcha/index'] - 若使用路由定义,确保验证码路由未被
cache中间件包裹;检查route/route.php,避免类似Route::get('captcha', 'index/captcha/entry')->cache(3600);的写法 - 更稳妥的做法:在验证码控制器方法开头强制关闭当前请求的缓存输出:
if (function_exists('ob_end_clean')) ob_end_clean();(配合ob_clean()使用效果更稳)
确认验证码接口未被页面级缓存污染
即使路由没开缓存,如果验证码是嵌在某个开启了静态缓存的页面里(比如登录页启用了 [:html]),浏览器或代理可能把整个 HTML 连同 <img src="/captcha"> 一起缓存,导致图片 URL 不变、服务端实际没被调用:
- 前端 img 标签加时间戳防缓存:
<img src="%7B:url('captcha/entry')%7D?t=" date.now onclick="this.src='{:url('captcha/entry')}?t='+Math.random()"> - 后端在验证码方法中设置防缓存头:
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');<br>header('Pragma: no-cache');<br>header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
检查 runtime 目录下是否生成了错误的缓存文件
静态缓存有时会误将验证码响应写入 runtime/html/ 下,下次直接读取这个损坏的 HTML 文件,而非执行 PHP:
- 进入项目根目录,运行:
ls -l runtime/html/ | grep captcha
若发现类似captcha.html或带路径哈希的缓存文件,立即删除:rm -f runtime/html/captcha* - 临时禁用静态缓存验证问题:
注释掉application/config.php中的'html_cache_on' => true,改为false,重启测试。若此时验证码正常,即可锁定是缓存机制干扰 - 确保
runtime/html/目录权限允许 Web 进程写入但不执行——避免恶意缓存覆盖关键逻辑
别漏掉 Session 和 GD 库基础依赖
静态缓存只是表象,底层依赖一旦失效,缓存再关也白搭:
- 验证码依赖 Session 存储真实值,检查
application/tags.php中app_init是否包含\think\middleware\SessionInit::class;用session('test', 'ok'); dump(session('test'));验证是否可读写 - GD 库必须启用且支持 TrueType:
php -r "var_dump(gd_info()['FreeType Support']);"必须返回 bool(true);否则imagettftext()失效,图片为空 - 字体文件路径要绝对、可读、无 BOM:
推荐改用public/static/font/DejaVuSans.ttf,并在配置中硬编码指定:'font' => public_path('static/font/DejaVuSans.ttf')
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











