如何修复 ERROR_KEY_DOES_NOT_EXIST 与 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, post 或 base64 |
ERROR_BAD_PARAMETERS | 该方法所需的某个参数缺失 | 重新提交前先核对该方法的参数列表 |
ERROR_GOOGLEKEY | sitekey 被拒绝 | 从实时页面重新读取它,而不是从缓存源 |
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.
当求解器是一个你自己掌控的 本地验证码识别工具 时,这一整类问题都会变小:没有账户,没有余额,没有轮换的凭据,只有一个你能在眼前屏幕上直接读到的密钥。
