mews/captcha 是 Laravel 9/10 最稳图形验证码方案,需执行 vendor:publish、确保 session driver 非 array、GD 启用、APP_URL 与访问域名一致、img src 加防缓存参数、验证失败后调 Captcha::reset()。

直接用 mews/captcha 是当前 Laravel 9/10 项目里最稳、最省事的图形验证码方案,gregwar/captcha 虽轻量但 session 覆盖逻辑容易踩坑,不推荐新项目选用。
安装与配置必须跑完 vendor:publish
只执行 composer require mews/captcha 不够,Laravel ≥9.3 不再自动发布配置,漏掉这步会导致字体路径错、图片空白或 500 错误。
- 运行
php artisan vendor:publish --provider="Mews\Captcha\CaptchaServiceProvider"生成config/captcha.php - 确认
config/app.php中已注册Mews\Captcha\CaptchaServiceProvider::class(Laravel 9+ 通常自动完成) - 检查
config/session.php的driver不能是array,否则验证码值根本存不进 session - GD 扩展必须启用:运行
php -m | grep gd,没输出就去 php.ini 开extension=gd
前端显示图片时要防缓存和跨域
captcha_src() 返回的是相对 URL,如果 APP_URL 和实际访问域名不一致(比如本地用 http://localhost 但 Nginx 反代到 https://site.com),图片会 404 或触发跨域 cookie 丢失。
- 在
<img>的src后强制加随机参数:{{ captcha_src('default') }}?{{ time() }}或用 JS:this.src='{{ captcha_src('default') }}?'+Math.random() - 别把
captcha_src()写成硬路径如/captcha/default——它依赖路由绑定,改了配置名就挂 - 表单提交必须带
@csrf,且方法为POST;GET 请求不会触发captcha验证规则
captcha 规则校验失败的真正原因
报错 The captcha is invalid 几乎从来不是前端输错了,而是后端 session 没对上。这个规则内部调用的是 Captcha::check(),它从当前 session 读 captcha/default 键,比对明文值后自动清空该键——所以同一张图只能提交一次。
- 验证规则必须写成
'captcha' => 'required|captcha',不能加string或alpha_num,否则预处理会破坏原始输入格式 - 不要在验证失败后只
return back(),得手动调Captcha::reset(),否则用户刷新页面后 session 里还残留旧值,新图无法通过校验 - 如果用了 Redis session,确认 Redis 连接正常;file driver 下检查
storage/framework/sessions目录可写 -
config/captcha.php中的expire单位是「分钟」,默认 60,设太小(比如 1)会导致刚生成就过期
别碰 math 模式和自定义字体路径
math 配置项开启后生成算术题(如 “3 + 7 = ?”),但 mews/captcha 对数学表达式没有做括号优先级或负数保护,用户输 “10” 可能被当成错——除非你重写 MathCaptcha 类,否则建议关掉。
- 字体文件路径默认指向
resources/fonts,但包里没自带字体;若不发布配置或没放真字体文件,会回退到 GD 默认点阵字,导致文字糊成一团 - 想换字体?把 ttf 文件放进
public/fonts/,然后在config/captcha.php里改'font' => public_path('fonts/your.ttf') - 别在控制器里用
echo captcha()或print_r(captcha()->create()),必须走response()或视图,否则破坏 HTTP 头导致图片加载失败
session 驱动、GD 状态、URL 域名、缓存参数——这四点对不上,验证码就一定挂,跟代码写得多漂亮没关系。


















