HTTP-клиент 1С: таймаут — часть бизнес-логики
Запрос, который «просто отправляет документ», однажды завис на 20 минут. Кассир нажал кнопку ещё три раза — и партнёр получил четыре заявки.
У внешнего вызова всегда есть две независимые части: транспорт и бизнес-результат. Ответ 200 означает, что сервер сумел ответить по HTTP; он не гарантирует, что заявка принята. Ошибка соединения, наоборот, не доказывает, что операция не выполнилась: сервер мог сохранить заявку и потерять ответ на обратном пути.
Сначала классифицируем исходы
- 2xx: читаем тело и проверяем прикладной статус.
- 400/422: запрос не пройдёт после простого повтора; данные уходят на исправление.
- 401/403: останавливаем поток и проверяем секрет или права.
- 429: уважаем ограничение частоты и
Retry-After. - 5xx и сетевой сбой: возможен ограниченный повтор, только если операция идемпотентна.
Эту таблицу полезно согласовать с владельцем API до разработки. Без неё программист невольно превращает все ошибки в один текст «сервис недоступен», хотя оператору нужны разные действия.
Один вызов — один объект результата
Не разбрасывайте разбор статусов по формам и регламентным заданиям. Обёртка клиента должна вернуть вызывающему коду структуру: выполнен ли транспортный вызов, HTTP-код, прикладной код, безопасное сообщение и идентификатор запроса. Тело ответа целиком в журнал не пишем: там могут оказаться персональные данные.
Функция ОтправитьЗаявку(ТелоJSON, КлючИдемпотентности) Экспорт
Соединение = Новый HTTPСоединение("partner.example", 443,,,, 20,
Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/api/v1/requests");
Запрос.Заголовки.Вставить("Content-Type", "application/json");
Запрос.Заголовки.Вставить("Idempotency-Key", КлючИдемпотентности);
Запрос.УстановитьТелоИзСтроки(ТелоJSON, КодировкаТекста.UTF8);
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
Возврат Новый Структура("Успех,МожноПовторить,Код,Сообщение",
Ложь, Истина, 0, "Сетевой сбой");
КонецПопытки;
Успех = Ответ.КодСостояния >= 200 И Ответ.КодСостояния < 300;
МожноПовторить = Ответ.КодСостояния = 429
Или Ответ.КодСостояния >= 500;
Возврат Новый Структура("Успех,МожноПовторить,Код,Сообщение",
Успех, МожноПовторить, Ответ.КодСостояния, "Ответ внешнего API");
КонецФункции
Таймаут 20 секунд здесь не универсальная рекомендация. Его выбирают по пользовательскому сценарию и договорённости с партнёром. Для кнопки в форме даже 20 секунд мучительно долго; такую операцию лучше поставить в очередь и показать статус. Для ночной сверки допустим другой бюджет времени.
Повторяем не «три раза», а по политике
Мгновенные повторы создают дополнительную нагрузку именно в момент аварии. Используем возрастающие интервалы, например 30 секунд, 2 минуты, 10 минут, и добавляем небольшой случайный разброс. Число попыток и следующую дату храним вместе с заданием, а не в памяти фонового процесса.
Повтор POST безопасен только при поддержке ключа идемпотентности. Один и тот же ключ отправляется при всех попытках одной бизнес-операции. Новый ключ после таймаута уничтожает защиту: партнёр справедливо сочтёт запрос новым.
Секреты и журнал
Токен должен жить в защищённой настройке, а не в модуле и не в пользовательском параметре. В журнале достаточно имени интеграции, correlation ID, HTTP-кода, длительности и номера попытки. Заголовок Authorization и полное тело запрещены. Для отладки сохраняют обезличенный фрагмент или хеш полезной нагрузки.
Минимальный тест клиента включает пять заглушек: быстрый 200, медленный ответ дольше таймаута, 422 с понятной ошибкой, 429 с паузой и 503 после того, как партнёр уже сохранил заявку. Последний сценарий показывает, почему транспортный сбой нельзя трактовать как отсутствие результата.
Практика: нарисуйте таблицу решений для вашего API. Для каждого класса ответа укажите: повторяем ли запрос, когда, сколько раз, что видит пользователь и кто получает уведомление.