Наша собственная статистика посещений включена всегда. Google Analytics помогает нам понять, как пользуются нашими публичными страницами (но не вашим рабочим пространством после входа), и включается только с вашего разрешения. См. нашу политику конфиденциальности.

Обработка ошибок API: от кодов 401 и 422 до ограниченного самовосстановления

Как различать ошибки аутентификации и авторизации, недоступные возможности, ошибки параметров и неизвестные результаты, исправлять запросы по актуальному каталогу и ограничивать повторные попытки с помощью модуля принятия решений, который не отправляет сетевых запросов, чтобы обработка ошибок не приводила к несанкционированному повышению привилегий или дублированию вызовов.

Когда запрос завершается ошибкой, главный вопрос для клиента звучит не «сколько ещё раз можно попробовать?», а «выполнился ли запрос и что нужно изменить, чтобы повторная попытка имела смысл?». Отсутствующий ключ, неверное название платформы, неподдерживаемый параметр и обрыв соединения во время потоковой передачи ответа могут попасть в один и тот же блок catch. Если обрабатывать все эти случаи одинаковыми повторными попытками, исправимые ошибки во входных данных будут повторяться, а уже созданные задачи могут продублироваться.

В этой статье на примере REST-интерфейса EveryInfra описаны разделение ошибок по уровням, сверка с актуальным каталогом и методы ограниченного самовосстановления. Пример модуля принятия решений выдаёт только рекомендации по следующему шагу: он не отправляет запросы, не переключает учётные данные и никогда автоматически не расширяет область данных. Текущий исходный код, бесплатные публичные пробные запросы и исторические примеры из бизнес-практики используются раздельно, чтобы не делать выводы обо всём поведении системы при сбоях аутентифицированных запросов на основании единственного ответа 400.

Сохраните попытку, прежде чем разбирать ошибку

Перед вызовом сгенерируйте идентификатор бизнес-операции, чтобы связать несколько попыток, предпринятых с одной целью. Для каждой попытки сохраняйте время начала и окончания, версию запроса, целевые возможности, код состояния HTTP и доступные идентификаторы запросов сервиса. Идентификатор бизнес-операции не является серверным ключом идемпотентности. Если сервис не заявляет о поддержке такого ключа, нельзя считать, что повторная отправка запроса с этим идентификатором приведёт к дедупликации.

Тело ответа может содержать HTML или обычный текст, быть пустым либо содержать JSON, который не удаётся разобрать. Перед разбором ошибки проверьте Content-Type и HTTP-статус. Если разбор не удался, сохраните минимальную диагностическую сводку. Не вставляйте исходные страницы ошибок напрямую в пользовательские промпты и не передавайте их агентам как инструкции. По умолчанию журналы не должны содержать ключи, полные подписанные URL, исходные тела ответов и другие ненужные персональные данные.

Текущий публичный формат ответа EveryInfra с ошибкой содержит error.code, error.message и error.request_id. Стройте обработку на основе кодов и HTTP-статусов, а сообщения воспринимайте как текст для людей. Не рассчитывайте, что сообщения на английском останутся неизменными, и не переходите автоматически по первому найденному в строке URL, передавая при этом учётные данные.

Для списков разрешённых диагностических полей можно опираться на OWASP Logging Cheat Sheet: используйте идентификаторы взаимодействия для связывания событий и маскируйте токены, значения сессий и конфиденциальные данные. Журнал ошибок должен давать достаточно контекста, чтобы найти попытку, но не становиться ещё одним источником учётных данных или копий данных клиентов.

401 и 403: обрабатывайте аутентификацию и авторизацию по отдельности

HTTP 401 означает отсутствие действительных учётных данных для аутентификации; 403 означает, что сервер отказал в выполнении. Статусы протокола задают общий смысл, а конкретная причина зависит от кодов ошибок продукта. В текущей реализации EveryInfra отсутствующий, недействительный или просроченный ключ относится к проблемам аутентификации, а ограничения по продуктам, отдельным возможностям и исходным IP-адресам относятся к проблемам авторизации.

Сначала проверьте, дошёл ли запрос до нужного сервиса, соответствуют ли заголовки Authorization требованиям сервиса и получает ли запущенный процесс конфигурацию из ожидаемого окружения. Проверяйте наличие переменных и флаги конфигурации, не выводя секреты. Активная авторизованная сессия в консоли, открытой в браузере, не доказывает, что серверный процесс получил правильный API-ключ.

При повторяющихся сбоях аутентификации приостановите затронутые задачи и уведомите владельца; не перебирайте другие ключи, не переключайте аккаунты и не отключайте ограничения прав ради восстановления. Автоматическое обновление применимо только к явно разрешённым сценариям, которые поддерживает продукт; долгоживущие API-ключи нельзя считать самообновляемыми токенами.

Неверное название возможности: сначала получите список кандидатов, затем проверьте целевой вариант

Публичную ошибку без ключа можно увидеть так. Здесь намеренно передаётся устаревший идентификатор google_maps только для чтения каталога, без сбора отзывов о местах:

Проверьте статус и тело ошибки для неизвестной платформы
curl --silent --show-error --include --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=google_maps'

При проверке 2026-09-04 в 20:46 (по пекинскому времени) был получен HTTP 400: error.code имел значение unknown_capability, а сообщение содержало google_maps_reviews и ещё одного близкого кандидата. Неизвестные возможности нельзя во всех случаях сопоставлять с кодом 404, а исходную задачу нельзя автоматически переключать только потому, что один из кандидатов оказался первым в списке.

Если исходная задача касается именно отзывов о местах, проверьте, возвращает ли google_maps_reviews отзывы, какую структуру URL эта возможность требует и соответствуют ли её выходные данные исходным требованиям. Алгоритмы подбора кандидатов учитывают только сходство названий и не понимают бизнес-намерения; магазины приложений и отзывы о местах не являются взаимозаменяемыми источниками данных.

422: приведите входные данные в соответствие с текущими параметрами

422 обычно означает, что содержимое запроса понятно, но содержащиеся в нём инструкции невозможно обработать. Приложениям следует дополнительно различать отсутствующие поля, нераспознанные поля, недопустимые значения перечислений и превышение ограничений размера. Способы исправления различаются: если отсутствует URL, нужно указать реальный целевой адрес; неизвестный вариант сортировки требует проверки параметра; слишком большие входные данные требуют подтверждённого способа разбиения на части, а не молчаливого отбрасывания половины исходного материала.

Сузьте запрос до конкретной платформы, чтобы проверить параметры
curl -fsS --max-time 30 \
  'https://api.everyinfra.com/api/v1/social/catalog?platform=douyin' \
  | jq '[.capabilities[] | {
      action, required_params, optional_params, param_meanings, max_limit
    }]'

Текущая реализация возвращает unknown_param для неизвестных параметров и invalid_value для неподдерживаемых значений перечислений, вместе с подсказками по исправлению. Однако параметры с одинаковыми названиями могут различаться в разных действиях, поэтому общая таблица параметров не заменяет справку по параметрам каждого действия. required_params, optional_params и допустимые значения нужно оценивать вместе, а общие ограничения на размер списка не являются обязательствами по пагинации.

После исправлений создайте новую версию запроса, сохранив исходную ошибку и обоснование изменений. Применяйте сопоставления автоматически, только если исходное намерение явно сохраняется; при нескольких кандидатах, отсутствии реальной цели, расширении временного диапазона или смене модели решение должен принимать человек. Заполнение отсутствующих полей догадками модели не является безопасным самовосстановлением.

402 и 429: не выдавайте проблемы с квотой за превышение лимита запросов

Сейчас EveryInfra использует 402 quota_exhausted для обозначения недостаточной квоты; это соглашение конкретного продукта, а не универсальное бизнес-значение кода 402 для всех сервисов. Проблемы с квотой требуют вмешательства владельца аккаунта; снижение числа параллельных запросов не увеличивает баланс автоматически, а клиентские приложения не должны автоматически пополнять баланс или переносить учётные данные.

429 сигнализирует о превышении лимита запросов. Если ответ содержит корректный заголовок Retry-After, соблюдайте указанное в нём время ожидания; отсутствие этого заголовка не означает, что можно немедленно выполнять частые повторные попытки, и не позволяет самостоятельно назначать срок восстановления сервиса. Интервалы между повторными попытками, джиттер, максимальное число попыток и крайние сроки должны быть явно заданы политиками приложения.

Стратегии соблюдения лимитов запросов должны охватывать все рабочие процессы, использующие общую квоту. Если один воркер снижает темп, а остальные продолжают отправлять запросы, перегрузка не исчезнет. Это рекомендация по планированию запросов на стороне приложения; она не означает, что API координирует несколько клиентских процессов за вас.

Ошибки 5xx, обрывы соединения и отправленные задачи: сначала проверьте статус выполнения

Ошибку 5xx нельзя просто трактовать как «ничего не произошло». Сервис мог принять запрос, сформировать частичные результаты или завершить этапы списания, а клиент так и не получил полный ответ. Если нет явных гарантий идемпотентности или доказательств выполнения, зафиксируйте результат как неизвестный и проверьте его по идентификаторам запроса, а не отправляйте POST повторно автоматически.

Если доступен job_id или предоставленный сервисом эндпоинт для запроса статуса, в первую очередь запрашивайте исходную задачу. Состояния «выполняется», «завершается», «успешно», «сбой» и ошибки самого запроса статуса нужно обрабатывать по отдельности; ответ 404 на запрос статуса может быть связан с идентификационными данными или областью доступа и не должен приводить к созданию новой задачи взамен. Убедитесь, что запросы статуса выполняются с идентификационными данными, соответствующими исходному запросу.

Даже после HTTP 200 нужно проверять бизнес-содержимое ответа. В MCP добавляются уровни ошибок JSON-RPC и инструментов, поэтому стратегий, рассчитанных только на REST, недостаточно. Пустые наборы, частичные результаты и аномальные ответы сохраняют собственные состояния и не помечаются все подряд как успешные, а итоговое списание нельзя вычислить только по статусу на стороне клиента.

Шаблон Retry от Microsoft напоминает о главном: повторяйте запросы только после устранимых сбоев, учитывая идемпотентность операций и наложение уровней повторных попыток. Если SDK, очереди и бизнес-уровень повторяют запросы независимо друг от друга, общее число попыток может превысить бюджет. Решения должен принимать один уровень, которому доступен весь контекст, вместо того чтобы каждый уровень по умолчанию повторял попытку.

Движок решений, который выбирает маршрут, но не выполняет повторные попытки

Ниже приведён офлайн-пример прикладного уровня, а не SDK EveryInfra. Входные данные должны поступать из записей о REST-попытках, для которых уже выполнен разбор протокола; retry_after_policy_check следует задавать только на основании фактических контрактов интерфейса или явного подтверждения того, что запрос не выполнялся. Его нельзя произвольно включать по решению модели или на основании текста ошибки. attempts хранит число предыдущих попыток.

Офлайн-скрипт на JavaScript: сохранение проверки авторизации и бюджета повторных попыток
function nextStep({status, hasJob = false, replaySafe = false,
                   attempts = 1, maxAttempts = 3}) {
  if (status !== null && (!Number.isInteger(status) || status < 100 || status > 599)) {
    throw new Error("invalid HTTP status");
  }
  if (typeof hasJob !== "boolean" || typeof replaySafe !== "boolean"
      || !Number.isSafeInteger(attempts) || attempts < 1
      || !Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
    throw new Error("invalid decision inputs");
  }
  if (status === 401 || status === 403) return "authorization_review";
  if (status === 402) return "account_review";
  if (hasJob) return "inspect_existing_job";
  if (status === 400 || status === 422) return "revise_request";
  if (status === 429 || status === null || (status >= 500 && status <= 599)) {
    return replaySafe && attempts < maxAttempts
      ? "retry_after_policy_check"
      : "inspect_attempt";
  }
  if (status >= 200 && status < 300) return "validate_delivery";
  return "manual_review";
}

// synthetic attempt; contains no network calls.
console.log(nextStep({status: 503}));
console.log(nextStep({status: 429, replaySafe: true, attempts: 3}));
console.log(nextStep({status: 202, hasJob: true}));

Три результата означают соответственно: проверить текущую попытку, проверить попытки после исчерпания бюджета и запросить статус исходной задачи. retry_after_policy_check не является командой немедленно повторить запрос; внешние уровни должны также проверить время ожидания, глобальные лимиты запросов и разрешённую пользователем область операций. Новые попытки после корректировки параметров учитываются в общем бизнес-бюджете, и нельзя зацикливаться бесконечно за счёт сброса счётчика.

Проверить, что система останавливается, так же важно, как проверить восстановление

  • Недействительная аутентификация: система не обращается к другим учётным данным и не запускает повторные попытки на бизнес-уровне.
  • Неоднозначные варианты возможностей: система сохраняет исходные цели, требует проверки и блокирует автоматическое переключение продукта.
  • Принятые запросы с прерванным ответом: исходные попытки и задачи сохраняются без создания дубликатов.
  • Сбой сохраняется после исправления параметров: новые версии фиксируются с соблюдением общего бюджета попыток.
  • Ошибки не в формате JSON, отсутствующие идентификаторы запроса, неизвестные коды: система переходит к консервативной обработке, не завершаясь с ошибкой и не объявляя результат успешным без оснований.
  • Данные возвращены, но бизнес-цель не достигнута: сохраняются статус доставки и вопросы для дальнейшей проработки, без одностороннего заявления о восстановлении баланса.

Поддерживайте небольшой набор образцов ошибок и прогоняйте его повторно при обновлении SDK, изменении параметров API или смене стратегии аутентификации. Тесты исходного кода проверяют ожидаемые последовательности, но для продакшен-развёртываний нужны доказательства на ограниченных реальных входных данных, причём дата каждой проверки фиксируется отдельно. Не подменяйте актуальную бизнес-приёмку с аутентификацией старыми скриншотами или ошибками из бесплатного каталога.

Безопасное самовосстановление нужно для того, чтобы явно исправимые проблемы реже отвлекали людей, а выполнение вовремя останавливалось там, где действительно требуется решение человека. Если на каждом шаге понятно, где произошла ошибка, что изменилось, выполнялась ли операция и почему следующий шаг разрешён, сообщения об ошибках становятся полезным инструментом интеграции, а не поводом для бесконечных повторных попыток.

Справочник LF-12