Как исправить ERROR_WRONG_USER_KEY и ещё 3 ошибки запроса

error_wrong_user_key означает, что ваш API-ключ так и не вышел за пределы вашего кода. В этом весь диагноз, и сказать об этом стоит сразу, потому что почти все читают его как «мой ключ неверный» и начинают вставлять новый. Для неверного ключа у CapSkip есть отдельный код. Сам error_wrong_user_key и три соседних кода возвращаются ещё до того, как решатель вообще посмотрел на капчу: они описывают форму отправленного вами HTTP-запроса, а не ту задачу, к которой он относился.
Четыре кода и тот, с которым их путают
Они приходят от эндпоинта отправки или эндпоинта опроса обычным текстом вместо привычного ответа OK. Каждый из них детерминирован. Повтор одинакового запроса даёт одинаковый ответ, поэтому цикл повторов вокруг любого из них тратит время впустую. Во второй строке ниже приведён соседний код, который в четвёрку не входит, потому что отличить эти два кода друг от друга и составляет основную часть работы.
| Код | Официальное значение | Что это значит на практике |
|---|---|---|
| ERROR_WRONG_USER_KEY | API-ключ отсутствует или пуст | Параметр key отсутствовал или пришёл с пустым значением |
| ERROR_KEY_DOES_NOT_EXIST | Недействительный API-ключ | Ключ пришёл, но CapSkip его не распознаёт |
| ERROR_WRONG_METHOD | Недопустимый HTTP-метод или параметр action | Значение method не из тех, что знает CapSkip, либо action не равен get |
| ERROR_WRONG_ID_FORMAT | Неверный формат идентификатора капчи | Идентификатор, с которым вы опрашивали, не является голым числом |
| ERROR_BAD_PARAMETERS | Отсутствуют или некорректны обязательные параметры | Обязательное поле для этого типа капчи отсутствует или задано неверно |
Полный список, включая коды загрузки изображений и коды, специфичные для reCAPTCHA, приведён в документации CapSkip API.
ERROR_WRONG_USER_KEY: ключ отсутствует, а не неверен
Отсутствующий и недействительный ключ представляют собой две разные ошибки с двумя разными решениями, и CapSkip разделяет их намеренно. Если ключ дошёл до сервера и не был распознан, вы получите error_key_does_not_exist, о котором написано в руководстве по этому коду. Если же вы получаете error_wrong_user_key, значит не пришло ничего распознаваемого, поэтому перестаньте смотреть на значение и посмотрите, отправлялось ли оно вообще.
# No key parameter at all. This is what produces it. curl -X POST \ -d "method=userrecaptcha" \ -d "googlekey=YOUR_SITEKEY" \ -d "pageurl=https://example.com/page-with-recaptcha" \ http://127.0.0.1:8080/in.php ERROR_WRONG_USER_KEY
Его вызывают четыре причины, примерно в порядке убывания частоты:
- Переменная окружения, не заданная там, где выполняется код. Классический вариант: она есть в оболочке и её нет в службе. Значение читается как пустая строка, и клиент отправляет key, за которым ничего нет.
- Ключ, прочитанный из конфигурационного файла, который не выкатили вместе с кодом.
- Самописный клиент, который добавляет key только тогда, когда переменная истинна, поэтому пустая строка молча убирает параметр.
- Клиент, который кладёт параметры туда, откуда запрос их не донесёт: например, тело JSON на эндпоинте, который читает поля формы.
Перед вызовом печатайте не само значение, а его длину. Нулевая длина скажет вам всё нужное и не положит учётные данные в лог-файл.
Почему это начинается только на сервере
Вот момент, который сбивает с толку тех, кто месяцами гоняет один и тот же код. CapSkip требует ключ только тогда, когда в приложении включена проверка API-ключа. На свежей локальной установке она выключена, поэтому запрос вообще без ключа принимается и никто ни на что не жалуется. Ваш клиент мог отправлять пустой ключ с того самого дня, когда вы его написали.
Потом вы переносите решатель на машину, которая стоит не у вас на столе. У CapSkip два режима подключения: Local привязывается к 127.0.0.1 и отвечает только этому устройству, а Server привязывается к вашему сетевому или публичному IP, поэтому другая машина, VPS или размещённый воркер могут обратиться к нему через API. Статический публичный IP сохраняет этот адрес неизменным. Оба режима описаны в разделе Настройки подключения. Включить проверку ключа при этом переходе правильно, и это же тот момент, когда все скрытые ошибки с ключом в вашем коде всплывают разом. В обоих случаях это по-прежнему ваше оборудование и по-прежнему без тарификации, поэтому речь идёт об изменении настройки, а не о том, сколько вы платите.
Если вы раздаёте ключи нескольким воркерам, выдайте каждому собственный, чтобы один ключ можно было отозвать, не трогая остальные. Эта сторона вопроса разобрана в руководстве по выдаче API-ключей для капчи.
ERROR_WRONG_ID_FORMAT: скорее всего вы отправили весь ответ целиком
У этой ошибки есть одна главная причина, и заметить её легко, если про неё знаешь. Эндпоинт отправки отвечает не голым числом. Он отвечает словом OK и идентификатором через вертикальную черту, и клиент, который передаёт эту строку прямо в запрос опроса, отправляет идентификатор, который числом не является.
# What in.php actually returns: OK|212 # Wrong. The whole reply went into id. curl "http://127.0.0.1:8080/res.php?key=YOUR_API_KEY&action=get&id=OK|212" ERROR_WRONG_ID_FORMAT # Right. Split on the pipe and send the number. curl "http://127.0.0.1:8080/res.php?key=YOUR_API_KEY&action=get&id=212"
Запросите JSON, и разбор станет менее хрупким, потому что идентификатор придёт полем, а не половиной строки с разделителем. В любом случае проверяйте префикс перед разбиением, потому что в коде ошибки вертикальной черты нет, и слепое разбиение вернёт вам код ошибки в роли идентификатора.
# A hand rolled client has to do this itself. The SDK does not,
# which is most of why it is worth using.
reply = httpx.post(IN_URL, data=payload).text # "OK|212"
if not reply.startswith("OK|"):
raise RuntimeError(reply) # it is an error code
captcha_id = reply.split("|", 1)[1] # "212"Разобранный пример цикла сырого запроса и опроса с той же обработкой разделителя есть в пошаговом разборе решения капчи через curl.
ERROR_WRONG_METHOD: не тот глагол или не то слово
Этот код делят между собой две разные ошибки, поэтому он и выглядит расплывчатым. Первая касается HTTP-глагола: параметры, отправленные телом формы на эндпоинт, который вы вызвали через GET, не приходят никуда. Вторая касается самого параметра method, значение которого должно быть одним из тех, что CapSkip распознаёт для решаемого типа: post или base64 для изображения, userrecaptcha для reCAPTCHA любой версии, turnstile для Cloudflare, geetest для GeeTest v3.
Большую часть случаев дают две опечатки: отправка sitekey на эндпоинт reCAPTCHA, которому нужен googlekey, и отправка recaptcha или userecaptcha вместо userrecaptcha. Этот же код покрывает и сторону опроса, где action должен быть буквальной строкой get.
ERROR_BAD_PARAMETERS: тип и поля не сходятся
Значение method понято, а что-то обязательное для него отсутствовало или было задано неверно. Проверка идёт по типу, поэтому полезный вопрос всегда один: какой тип, по мнению CapSkip, вы запросили.
- reCAPTCHA нужны и googlekey, и pageurl, причём pageurl должен быть полным URL страницы, на которой загружается виджет, вместе со схемой.
- reCAPTCHA v3 нужен version со значением v3. Отправив вместе с ним invisible, вы кладёте поле от v2 в запрос v3.
- Страницам проверки Turnstile нужны data и pagedata помимо sitekey. Режиму виджета не нужно ни то, ни другое.
- GeeTest нужны gt и challenge вместе, причём challenge истекает примерно за минуту, поэтому устаревшее значение отваливается уже здесь, а не позже.
- Графическим капчам нужен file для multipart-загрузки или body для base64, и никогда оба сразу.
Залогируйте полезную нагрузку, которую собираетесь отправить, скрыв ключ, и сверьте её с таблицей параметров для этого типа. В девяти случаях из десяти ответ виден в этой одной строке.
Пустой ответ к ним не относится
Опрос, который не возвращает вообще ничего, представляет собой другую ситуацию, и назвать её стоит, потому что пустой ответ принимают за неверный идентификатор. Пустое тело означает, что результат уже забрали, либо что идентификатора не существует. CapSkip позволяет прочитать результат один раз. Цикл повторов, который отработал успешно, а затем пошёл на новый круг, потому что в коде забыли про break, во второй раз читает пустую строку и сообщает об ошибке на капче, решённой правильно.
Сохраняйте результат сразу, как только получили его в первый раз. И не путайте пустой ответ с CAPCHA_NOT_READY: это нормальное состояние опроса, а не сбой, и описано оно в руководстве по этому ответу.
Как читать эти коды из SDK
Каждый из четырёх кодов приходит в виде ApiException, где сообщением служит сам код. Именно это исключение стоит проверять первым, потому что оно означает, что CapSkip вас понял и отказал, а это уже другой класс проблемы, чем полная невозможность достучаться до CapSkip.
# pip install capskip
from capskip import CapSkip, ApiException, NetworkException
solver = CapSkip(host="127.0.0.1", port=8080, apiKey=API_KEY)
try:
token = solver.recaptcha(sitekey=SITEKEY, url=PAGE_URL)["code"]
except ApiException as err:
# CapSkip answered and rejected the request. Do not retry.
print("Rejected:", err)
except NetworkException as err:
# CapSkip did not answer. Wrong host, wrong port, or not running.
print("Unreachable:", err)Про ValidationException здесь тоже стоит знать, потому что оно срабатывает ещё до того, как что-либо отправлено. SDK отклоняет параметры, неподходящие для запрошенного типа, поэтому ошибка, которая по сырому HTTP вернулась бы как ERROR_BAD_PARAMETERS, ловится локально, причём в сообщении назван сам аргумент. Всего в SDK четыре типа исключений: ApiException, NetworkException, TimeoutException и ValidationException. Каждый из них наследуется от базового CapSkipError, если вам удобнее обрабатывать их в одном месте. Те же четыре есть в клиентах для Node.js, PHP и C#, перечисленных на на странице SDK для распознавания капчи.
FAQ
В чём разница между ERROR_WRONG_USER_KEY и ERROR_KEY_DOES_NOT_EXIST?
В том, дошёл ли ключ. Первый означает, что параметр key отсутствовал или был пуст, поэтому смотрите на свою конфигурацию и на сборщик запроса. Второй означает, что ключ дошёл и CapSkip его не распознаёт, поэтому смотрите на значение и на то, какой ключ приложение выдаёт на самом деле.
Нужен ли мне API-ключ вообще?
Только когда в приложении CapSkip включена проверка API-ключа. По умолчанию она выключена, и это нормально на машине, где решатель отвечает только на loopback. Включите её до того, как решатель начнёт слушать сетевой адрес, и с этого момента отправляйте ключ.
Стоит ли повторять любой из этих запросов?
Нет. Все четыре детерминированы, поэтому вторая попытка проваливается ровно так же, как первая. Повторяйте вместо них временные сбои: ошибку соединения, таймаут опроса или капчу, вернувшуюся как нераспознаваемая. Повтор некорректного запроса просто тратит запас отступов на ошибку в коде.
Локально всё работало, а на сервере сломалось. Почему?
Почти всегда потому, что вместе с переездом включилась проверка ключа, а ключ на самом деле никогда и не отправлялся. Вторая по частоте причина: переменная окружения, которая есть в вашей оболочке, но отсутствует в службе, запускающей код. Проверьте длину значения в точке вызова.
Коротко
Эти четыре кода говорят о вашем запросе, а не о капче. error_wrong_user_key означает, что в параметре key ничего не пришло, и это проблема конфигурации, а не неверного значения. ERROR_WRONG_ID_FORMAT почти всегда означает, что ответ с вертикальной чертой ушёл целиком. ERROR_WRONG_METHOD означает неверный глагол или неверное написание, а ERROR_BAD_PARAMETERS означает поле, которое не относится к запрошенному типу. Повторять не стоит ни один из них.
Таблицы параметров, которые закрывают каждый из этих случаев, есть на странице документации API. Клиент для Python, который убирает большую часть возможностей ошибиться, находится на странице сервиса распознавания капч для Python.
Стоит помнить, пока вы занимаетесь отладкой: CapSkip представляет собой обход капчи инструмент, который работает на вашем собственном оборудовании, поэтому некорректный запрос, отправленный сотню раз, пока вы разбираетесь, не стоит вам ничего, кроме потраченного времени.
