如何修复 ERROR_KEY_DOES_NOT_EXIST 与 Wrong User Key 错误

error_key_does_not_exist - How to Fix ERROR_KEY_DOES_NOT_EXIST and Wrong User Key

简短回答: ERROR_KEY_DOES_NOT_EXIST 表示请求中携带的 API 密钥不是求解器认识的密钥。验证码、sitekey 和页面 URL 都没有问题,请求根本没有走到求解那一步。本文讲清真正导致它的三种情况、四个 SDK 中的修复方式,以及为什么你有时看到的是 ERROR_WRONG_USER_KEY ,而不是前者。

ERROR_KEY_DOES_NOT_EXIST 是什么意思

它来自 /in.php,在提交阶段就返回,早于任何求解过程。API 会把请求中的 key 参数与它配置的可接受密钥做比对,结果没有找到匹配项。

# Submitting with a key the app does not know:
curl "http://127.0.0.1:8080/in.php?key=WRONG&method=userrecaptcha&googlekey=YOUR_SITEKEY&pageurl=https://example.com"

ERROR_KEY_DOES_NOT_EXIST

因为它在提交阶段就返回,你根本拿不到 captcha ID,也就没有任何东西可以在 /res.php上轮询。如果你的代码正在循环等待,它等的是一个从未被签发的 ID。

从托管服务转过来的人常会在这里绊一下:CapSkip 是一个 在你自己机器上运行的 2Captcha 兼容 API,所以这个密钥不是账户凭据,也不与任何余额绑定。它只是 API 服务端上的一次本地访问校验。这就改变了“密钥不对”可能意味着什么,也正因如此,下面的修复步骤都很短。

第一步,先确认密钥校验是否开启

CapSkip 的密钥校验是可选的。关闭时,任何非空字符串都能通过,你永远不会看到这个错误;开启时,密钥必须完全一致。

打开 CapSkip 应用,进入 Settings,找到 API server 一节。这里有两点要看:密钥校验是否启用,以及启用时确切的密钥字符串。请直接从这个界面复制密钥,而不要手敲。大多数关于 ERROR_KEY_DOES_NOT_EXIST 的反馈到这里就结束了。

既然已经在 Settings 里,顺便确认端口。端口错了给出的是连接错误而不是这个错误,但两者一起检查更省事。 设置指南 完整介绍了这个界面。

在各个 SDK 中正确传入密钥

四个 SDK 使用相同的选项名,也都读取同一个环境变量 CAPSKIP_API_KEY。调试时请显式设置它,这样就不必猜测究竟发送了什么。

# pip install capskip
from capskip import CapSkip

# apiKey defaults to "capskip", which only works when
# key validation is turned off in the app.
solver = CapSkip(
    apiKey="YOUR_API_KEY",
    host="127.0.0.1",
    port=8080,
)
// npm install capskip
const { CapSkip } = require('capskip');

const solver = new CapSkip({
  apiKey: 'YOUR_API_KEY',
  host: '127.0.0.1',
  port: 8080,
});
// composer require capskip/capskip
use CapSkip\CapSkip;

$solver = new CapSkip([
    'apiKey' => 'YOUR_API_KEY',
    'host'   => '127.0.0.1',
    'port'   => 8080,
]);
// dotnet add package CapSkip
using CapSkip;

var solver = new CapSkipClient(
    apiKey: "YOUR_API_KEY",
    host:   "127.0.0.1",
    port:   8080);

每个方法的完整签名见 CAPTCHA 识别 SDK 页面。

值得排查的三种原因

1. 密钥根本没有离开你的代码

你把 CAPSKIP_API_KEY 写进了一个 .env 文件,但运行时没有任何东西去加载 .env 。或者你在一个 shell 里导出了它,却在另一个 shell 里运行脚本。SDK 回退到默认值,而默认值不是你的密钥,于是就报这个错。

把即将发送的内容打印出来。一行代码就能定案:

import os

# Never print the whole key in a shared log.
key = os.environ.get("CAPSKIP_API_KEY", "<unset>")
print(len(key), repr(key[:4]))

打印长度能抓住被掩码遮住的情况:密钥存在但为空,或者尾部带了一个换行符,比如来自 cat key.txt.

2. 密钥是对的,但在 URL 里被弄坏了

这只会影响直接调用原始 API 的人。如果密钥里含有在查询字符串中具有特殊含义的字符,就必须做百分号编码。一个 + 会变成空格,一个 & 会提前结束参数,而一个 # 会把它后面的一切都截断。

# Wrong: curl sends this raw and the key gets cut at the &
curl "http://127.0.0.1:8080/in.php?key=ab&cd&method=userrecaptcha"

# Right: let curl encode the parameter for you
curl -G http://127.0.0.1:8080/in.php \
  --data-urlencode "key=ab&cd" \
  --data-urlencode "method=userrecaptcha"

或者干脆用 POST 以表单体发送参数,这样能绕开这一整类问题。MDN 上有一份简短的 百分号编码 参考,列出了确切的字符清单。SDK 会替你编码,所以只要换用 SDK,这个原因就消失了。

3. 你换过密钥,但还有东西握着旧的

长期运行的 worker、把密钥打进镜像的 Docker 容器、CI 里的 secret、单独配置的浏览器扩展。应用里已经是新密钥,某个调用方还拿着旧的,于是只有它失败。如果你的一部分请求成功、另一部分失败,几乎总是这个原因。

ERROR_KEY_DOES_NOT_EXIST vs ERROR_WRONG_USER_KEY

两个错误字符串,同属一类。把它们当成同一个问题的两种形态来处理。

错误它指向什么首先检查什么
ERROR_KEY_DOES_NOT_EXIST密钥被读到了,但与已知密钥不匹配密钥字符串本身,从 Settings 复制
ERROR_WRONG_USER_KEY密钥校验已开启,而发送的密钥不对先看校验是否开启,再看字符串

在 SDK 中两者都表现为 ApiException,所以捕获这一种类型并读取消息即可,不必按字符串分支。

from capskip import CapSkip, ApiException, NetworkException

solver = CapSkip(apiKey="YOUR_API_KEY")

try:
    result = solver.recaptcha(
        sitekey="YOUR_SITEKEY",
        url="https://example.com/page-with-recaptcha",
    )
except ApiException as e:
    # Key problems land here, with the raw code in the message.
    print("api rejected the request:", e)
except NetworkException as e:
    # The app is not running, or the port is wrong.
    print("cannot reach capskip:", e)

相邻的错误码

如果密钥没问题,提交阶段接下来的几种失败看起来相似,含义却完全不同。

代码原因修复
ERROR_WRONG_METHOD加载的 method 参数缺失或拼错使用 userrecaptcha, turnstile, geetest, postbase64
ERROR_BAD_PARAMETERS该方法所需的某个参数缺失重新提交前先核对该方法的参数列表
ERROR_GOOGLEKEYsitekey 被拒绝从实时页面重新读取它,而不是从缓存源
ERROR_PAGEURL页面 URL 缺失或格式不对发送包含协议头的完整 URL
Connection refused应用没有运行,或端口不一致启动 CapSkip,确认 API server 已开启

API 可能返回的每一个错误码都列在 API 文档.

常见问题

我到底需不需要 API 密钥?

只有在应用里开启了密钥校验时才需要。关闭时任何非空字符串都会被接受,SDK 默认的 capskip 就能正常工作。这个密钥是一次本地访问校验,不是账户。

ERROR_KEY_DOES_NOT_EXIST 会不会表示我的额度用完了?

不会。这里根本没有余额可以用完。求解在你自己的机器上进行,所以密钥错误永远是你发送的内容与应用期望的内容不一致。

轮询请求里也要带密钥吗?

可以。 /res.php 使用同样的 key 参数,和 /in.php一样。如果你只修了提交调用,轮询仍可能因为旧值而失败。

我原来的 2Captcha 密钥为什么在这里不管用?

因为它是他们的服务签发的,对运行在你自己机器上的求解器毫无意义。API 形态相同,凭据并不相同。把你的客户端指向 127.0.0.1 ,并使用 CapSkip Settings 里的密钥。

小结

确认密钥校验是否开启,从 Settings 复制密钥而不是手敲,确认这个值确实到达了你的进程,如果是手动拼 URL 就做好编码。这基本覆盖了 error_key_does_not_exist.

当求解器是一个你自己掌控的 本地验证码识别工具 时,这一整类问题都会变小:没有账户,没有余额,没有轮换的凭据,只有一个你能在眼前屏幕上直接读到的密钥。