Tutorials

在自有 QA 中安全地缓存与复用 CAPTCHA token

同一个 token 能不能在下一条 QA 用例里接着用?取决于是否已绑定具体请求、是否超过官方有效期 —— 判断清楚就能省掉一批不必要的重复求解,仅限自有内部 endpoint、有效期内使用。

安全范围: 本指南仅适用于你自有或经授权的 QA、staging 与预发布环境。内容覆盖针对你自己 CAPTCHA 集成的诊断、测试与可观测性模式 — 不涉及第三方站点或未授权流程。

三种 token 的有效期与能不能缓存

三种类型的 token 有效期都很短,规则也各不相同,直接决定缓存策略怎么定:

CAPTCHA 类型 Token 有效期 能否缓存 说明
reCAPTCHA v2 约 120 秒 有限 多数站点只接受同一 token 提交一次
reCAPTCHA v3 约 120 秒 有限 同一站点不同请求返回的分数可能不同
Cloudflare Turnstile 约 300 秒 有效期内可以 只要没过期,同一 token 可反复复用

Turnstile 窗口最宽松,最适合优先缓存;reCAPTCHA v2/v3 能否复用取决于站点校验逻辑,先测试再决定。

QA 缓存实现:按 TTL 管理内存字典

QaTokenCache 只做两件事:按 key 存 token,读取时检查是否过了自定义 TTL。TTL 要比官方有效期短一截 —— Turnstile 官方给 300 秒,内部设 90 秒更稳妥,避免用到临界失效的 token。

import time

class QaTokenCache:
    def __init__(self, default_ttl=90):
        self.store = {}
        self.default_ttl = default_ttl

    def get(self, key):
        item = self.store.get(key)
        if not item:
            return None
        token, exp = item
        if time.time() >= exp:
            self.store.pop(key, None)
            return None
        return token

    def put(self, key, token, ttl=None):
        self.store[key] = (token, time.time() + (ttl or self.default_ttl))

在内部 QA endpoint 校验缓存的 token

拿到 token 后(新求解或缓存读出),提交到 QA 后端 endpoint 校验 secret、sitekey 是否匹配,并记录命中率 —— 骤降通常是 TTL 设短了或参数未归一化。

观测指标:从命中率到全链路追踪

给每个 qa_case_id 记录 token 来源(缓存/新求解)、求解耗时、后端状态码;规模变大后加一层结构化日志和 correlation id(如 OpenTelemetry),按 id 重放场景可省一半排查时间。

常见故障排查

问题 处理方式
token 在 QA 环境中过期 只在有效期内复用,不在生产环境复用
backend 拒绝 token 比对 sitekey、action、secret 是否一致
内部缓存命中率偏低 检查 TTL 是否短于实际有效期,或参数未归一化
多 worker 结果不一致 换 Redis 等跨进程存储,统一 TTL 规则

上线前检查清单

  1. 测试范围限定在已获授权的资源。
  2. key 存放在 CI secret 仓库或 vault,不进源代码。
  3. 每次运行记录耗时与状态码。
  4. 瞬时错误配置幂等重试与上限。
  5. 测试能在 CI 中反复重现。

Python 示例:一次最小可运行的 QA 调用

在自己的 staging 环境里,用 CaptchaAI 跑通一次 CAPTCHA widget 测试的最小闭环:提交任务拿 taskId,再轮询拿最终 token。

import os
import requests

API_KEY = os.environ['CAPTCHAAI_KEY']
QA_PAGE_URL = os.environ['QA_PAGE_URL']  # 例如 https://staging.example.com/qa-login
QA_SITE_KEY = os.environ['QA_SITE_KEY']


def submit_qa_recaptcha() -> str:
    payload = {
        'clientKey': API_KEY,
        'task': {
            'type': 'NoCaptchaTaskProxyless',
            'websiteURL': QA_PAGE_URL,
            'websiteKey': QA_SITE_KEY,
        },
    }
    response = requests.post(
        'https://api.captchaai.com/createTask',
        json=payload,
        timeout=30,
    )
    response.raise_for_status()
    return response.json()['taskId']


def fetch_qa_result(task_id: str) -> dict:
    payload = {'clientKey': API_KEY, 'taskId': task_id}
    response = requests.post(
        'https://api.captchaai.com/getTaskResult',
        json=payload,
        timeout=30,
    )
    response.raise_for_status()
    return response.json()

常见问题

这套流程会不会碰到生产流量?

不会。所有示例都假设跑在 staging.example.com 这类已获授权的环境里,不直接对生产环境跑测试。

CaptchaAI key 能不能直接写进测试脚本?

不行。要通过 CI secret 管理器或 vault 注入;已提交进代码仓库的 key 必须立刻轮换。

reCAPTCHA v2 的 token 一定不能缓存吗?

不一定,看目标站点是否只做一次性校验。先用同一 token 重复提交测试,能通过再对该站点启用缓存。

轮询遇到瞬时错误该怎么重试?

幂等重试配合指数退避(1 秒、2 秒、4 秒)并设上限。网络错误、5xx 和 ERROR_NO_SLOT_AVAILABLE 适合重试;余额不足或 key 失效不应重试。

更多 QA 相关指南

在自己的环境里,用 CaptchaAI 验证这套缓存与复用流程。

该文章已禁用评论。