captcha.verifystring返回false大概率是服务端状态丢失或参数错位,常见原因包括前端传id不一致、默认内存存储重启失效、redis未设ttl、输入未trim、服务器时间不同步。

captcha.VerifyString 返回 false 到底是输错了还是服务端出问题
别急着怪用户输错,captcha.VerifyString 返回 false 大概率是服务端状态丢失或参数错位。常见原因有:
• 前端传的 id 和校验时用的不一致(大小写敏感、空格、URL 编码差异)
• 用了默认内存存储,服务重启后所有验证码立即失效
• Redis store 没设 TTL,或 key 过期时间没生效(比如用 SET 没带 EX 参数)
• 用户输入值没 strings.TrimSpace(input),粘贴带换行或空格直接失败
• 服务器时间不同步,time.Now().Unix() 判断过期时偏差过大
为什么不能复用同一个 captcha.DriverDigit 实例生成多个验证码
可以且必须复用——但不是“同一个”,而是“同一类驱动配置的实例”。base64Captcha.DriverDigit 初始化时会加载字体、创建绘图上下文,频繁 new 会导致:
• 字体文件重复 mmap,内存占用持续上涨
• 并发高时 rand.Seed 冲突(尤其未显式设置 seed)
• 图像噪点/旋转逻辑可预测,OCR 破解成功率上升
正确做法是全局初始化一个驱动实例,例如:var digitDriver = &base64Captcha.DriverDigit{Height: 60, Width: 200, Length: 4},后续所有 Generate() 都基于它
验证码 ID 绑定到什么才算真正防刷
只靠前端传来的 captchaId 校验,等于把门钥匙挂门口。必须绑定上下文:
• 有 session:生成时存 session.Set("captcha_id", id),校验前先比对 session.Get("captcha_id") == id
• 无 session(如 API 网关层):用 sha256.Sum256([]byte(c.Request.RemoteAddr + c.Request.UserAgent)).String()[:16] 作 key 前缀,再拼 id,避免 IP 池穿透
• 微服务间调用:在 gateway 层注入 X-Request-ID,将它作为存储 key 的一部分,确保跨服务链路可追溯
别用纯 IP——NAT 网关下千人共一 IP;也别只依赖 UA——易伪造
如何让 /captcha 接口不被 CDN 或浏览器预加载缓存
这是生产环境高频翻车点。一旦 CDN 缓存了 /captcha?id=xxx,用户还没点刷新,图片就已失效:
• 前端 <img> 必须加 fetchpriority="low" 和 referrerpolicy="no-referrer"
• URL 强制带时间戳参数:/captcha?id=xxx&t=1719826740(注意是 & 不是 &)
• Nginx 配置里明确禁用该路径缓存:location ^~ /captcha { add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0"; }
• 如果用 gin,别把 /captcha 路由套在任何中间件里(尤其是鉴权或日志中间件),防止 context 提前销毁
captcha.SetCustomStore,否则一半请求走内存、一半走 Redis,校验成功率直接腰斩。











