验证码任务一直 processing 怎么办:先分清“慢”和“卡”,再按顺序排查

2026-10-12 54

任务提交成功后,getTaskResult 一直返回 processing,常见原因主要有四类:

  • 等待时间本来就还没到,Token 类任务通常需要十几秒到几十秒;
  • 轮询代码有缺陷,比如没有总超时、漏处理错误字段、查错了 taskId;
  • 任务参数存在“软错误”,后端无法完成挑战;
  • 代理链路或目标站点出了问题。

排查建议从自己的代码查起,再核对参数,最后才怀疑代理、目标站和服务端排队。前几项最容易查,出问题的概率也最高。

不管原因是哪一类,轮询都要设总超时。按任务类型设一个上限(Token 类常见做法是 60–120 秒),到点就停止等待,记录 taskId,再按策略决定是否重新提交。

先判断:是“慢”,还是真的“卡”

createTask 返回 taskId,只说明任务已经入队,挑战还没有完成。之后任务状态在 processing 和 ready 之间切换,完成之前每次查询都会得到 processing 或类似的“未就绪”响应。

所以第一步是拿等待时间和任务类型对照:

  • 图形 OCR(ImageToText 一类):通常几秒内返回。等了 30 秒还没结果,基本可以按异常处理。
  • Token 类任务(reCAPTCHA v2/v3/Enterprise、Cloudflare Turnstile/Challenge、GeeTest v4、Arkose 等):后端要走完浏览器或协议层面的挑战流程,十几秒到几十秒都常见。如果按 OCR 的速度来预期,很容易误以为任务卡死了。

建议按类型分别统计等待时长的 P50 和 P95,不要只看平均值。假设某类任务的 P95 在 40 秒左右,30 秒的超时就会把一部分本来能成功的任务提前丢掉。反过来,如果 P50 从十几秒突然涨到一分钟,才说明有东西变了。

按顺序排查

1. 轮询代码本身有没有问题

不少“一直 processing”,查到最后是客户端的问题:

  • 没有总超时:循环只在 ready 时退出,遇到失败或异常的任务就会一直等下去。
  • 只看状态,不看错误字段:任务式接口的响应里通常同时有错误标识(errorId 一类字段)和状态。如果代码只判断“不是 ready 就继续等”,任务失败也会被当成 processing。
  • 查错了任务:并发时 taskId 被覆盖、复用了旧变量,或者查询用的密钥属于另一个账户。
  • 轮询太频繁:每秒查好几次可能触发频控。拿到 429 或被限流后,代码又把这类异常当成“未完成”。多家平台的文档都建议 3–5 秒查一次;有的平台还限制单个任务的查询次数,超过后可能被限流或丢弃。
  • HTTP 层出错:请求超时、中间代理缓存了响应、重试库吞掉了异常,最终都会表现为“一直拿不到结果”。

检查方法:每次查询都记录原始响应体、HTTP 状态码、taskId 和时间戳。如果原始响应里其实已经带了错误信息,问题就出在你的解析逻辑。

2. 任务参数和页面是否一致

参数错误不一定在 createTask 阶段就被拒绝。有些错误要到后端真正去完成挑战时才会暴露,表现为后端反复尝试,直到平台端超时。常见情况:

  • websiteKey 和页面实际加载的不一致。同一站点的不同页面、测试环境和生产环境,可能用的是不同的 key;
  • websiteURL 填的是跳转前的地址,没有用重定向后实际的协议、域名和路径;
  • 缺少上下文参数,例如 reCAPTCHA v3 的 pageAction、Enterprise 标记,或 Turnstile 的 action、cData;
  • 任务类型选错,比如把 Enterprise 当普通 v2 提交,或者把 Cloudflare 整页 Challenge 当成 Turnstile 组件处理。

参数最好从浏览器开发者工具里的实际网络请求中提取,这比在页面源码里搜索更可靠。具体提取方法可参考 Puppeteer 验证码接口怎么接。

3. 代理链路是否正常

如果用的是自带代理的任务类型,服务端要通过你提供的代理去访问目标站点。以下情况都可能让任务长时间停在处理中,或者多次网络重试后失败:

  • 代理认证失败或连接超时;
  • 出口 IP 被目标站返回 403/429;
  • 出口 IP 已被目标站风控。

对照方法:同一组参数,分别换一个确认可用的代理、或者改用无代理任务类型(前提是该类型支持),各提交几次。如果只有使用某个代理的任务卡住,问题就在代理。也可以先用这个代理直接打开一次目标页面,看能否正常加载。

4. 目标站变化与服务端排队

目标站更换了验证码接入方式,或者验证服务临时提高了难度(比如要求多轮选择),都会让同类任务整体变慢,服务端队列随之堆积。

这种情况的特征是:同一类型的任务,换了参数和代理也一样变慢,而其他类型正常。这时改自己的代码作用不大。应该记录时间窗口和一批 taskId 样本去联系服务商,业务侧同时降速或暂停。

验证码任务轮询状态流转与总超时兜底流程图

一个带兜底的轮询写法

下面是通用伪代码,不能直接运行。字段名和错误标识请以你所用平台的官方文档为准:

# 伪代码:按任务类型设置等待上限,数值按自己统计的 P95 调整
DEADLINE     = { 'image_ocr': 30, 'token_task': 120 }   # 秒
INITIAL_WAIT = { 'image_ocr': 2,  'token_task': 10 }    # 首次查询前等待
INTERVAL     = 4                                       # 秒,建议 3–5

function wait_result(task_id, task_kind):
    start = now()
    sleep(INITIAL_WAIT[task_kind])
    while now() - start < DEADLINE[task_kind]:
        resp = http_post(GET_RESULT_URL,
                         body = { clientKey: read_from_env(), taskId: task_id },
                         timeout = 10)
        if resp is network_error or resp.http_status == 429 or resp.http_status >= 500:
            log(task_id, resp)
            sleep(backoff())          # 网络/限流异常:退避后再查
            continue
        if resp.error_flag != 0:      # 任务已失败:立即退出,不要继续等
            return Failed(task_id, resp.error_code)
        if resp.status == 'ready':
            return Ready(task_id, resp.solution, elapsed = now() - start)
        sleep(INTERVAL)               # 仍在 processing:正常等待
    return TimedOut(task_id, elapsed = now() - start)

这段逻辑有几个要点:

  • 首次查询前先等一会儿。 Token 任务刚提交就查,只会多出无效请求。
  • 三种情况分开处理。 任务错误立即退出;网络异常或限流退避后再查;只有真正的 processing 才按正常间隔等待。
  • 返回值带上耗时和 taskId。 方便按类型统计 P50/P95,出问题时也能拿样本找服务商核对。
  • 密钥从环境变量或密钥管理服务读取。 不要写进代码、日志和截图。

如果用回调(webhook)代替轮询,本地仍然需要一个计时器,因为回调一直没到并不会自动变成失败信号。两种方式怎么选,见 验证码API轮询和回调有什么区别。

超时之后怎么处理

  • 先判断原因,再决定是否重提。 不要拿同样的参数立刻无限重提。如果是参数或代理的问题,重提只会重复失败。
  • Token 类任务要考虑页面状态。 浏览器页面停留太久,会话或页面上的挑战可能已经失效。重试前最好刷新页面,重新提取参数。
  • 给重试设上限。 比如最多重试一到两次,超过就记录并跳过,避免单个任务拖住整个批次。
  • 拿到结果不等于业务成功。 Token 返回后,目标站仍可能拒绝,这属于另一类问题,见 验证码 token 返回后验证失败怎么排查。连接超时、等待超时等不同超时的区分,可以看 验证码API超时怎么处理。
  • 确认计费口径。 弄清你所用的平台对超时任务、失败任务分别怎么计费,再决定重试策略能承受多少次额外提交。

在 NexCaptcha 上排查时

NexCaptcha 采用 createTask / getTaskResult 的任务模式,支持轮询和 webhook。API 域名是 api.nexcaptcha.net,密钥放在请求体的 clientKey 字段中。上面的排查顺序同样适用:

  1. 确认 clientKey 和 taskId 对应同一账户、同一任务,并且代码处理了错误字段;
  2. 核对任务类型和页面参数;
  3. 检查代理链路。

官网说明按千次成功识别计费、失败退款。超时任务具体怎么计入、错误标识字段的确切名称,以官方文档和工程师的答复为准。

如果反复核对后,同一类任务仍然持续卡住,可以整理好任务类型、出问题的时间段、几个 taskId 样本以及是否使用代理,通过 NexCaptcha 官网 的工程师联系入口提交,方便对方定位问题。

相关文章

滑块验证码识别接口升级:从简单坐标点击到高拟真轨迹模拟
打码平台费用对比:跳出“千次单价”陷阱,企业采购与迁移的总拥有成本(TCO)核算指南
从防爬升级看企业数据采集策略:为什么简单的OCR方案正在失效?
让 AI Agent 像人一样工作:通过 MCP 标准实现自动化验证码识别
腾讯验证码识别 API 怎么接:CaptchaAppId 提取、ticket/randstr 回调注入与动态风控应对实战