Ошибка выполнения POST-запроса в 1С: как найти причину за 5 минут
Ошибка выполнения POST-запроса в 1С — это либо исключение платформы
(не удалось установить соединение: SSL/TLS, таймаут, DNS, прокси), либо
ненулевой код состояния в объекте HTTPОтвет
(400, 401, 403, 404, 415, 500 и т.д.). Первое ловится через
Попытка/Исключение, второе — проверкой
Ответ.КодСостояния и чтением тела через
Ответ.ПолучитьТелоКакСтроку("UTF-8").
Универсальный шаблон: обернуть ОтправитьДляОбработки() в
Попытка, при успехе — проверить код и, если он не 2xx,
залогировать тело ответа в журнал регистрации. Без логирования тела
ошибка post 1с превращается в гадание.
Исключение vs код состояния: два типа ошибок POST в 1С
Когда говорят «post запрос ошибка 1с», в реальности путают две принципиально разные ситуации. От того, какая из них произошла, зависит и способ диагностики, и что именно чинить в коде обработки.
-
Исключение платформы. Соединение не установлено или прервано:
SSL-рукопожатие не прошло, недоступен DNS, не отвечает порт, истёк таймаут,
не пускает прокси. В этом случае метод
ОтправитьДляОбработки()выбрасывает исключение — объектаHTTPОтветне будет. -
Ошибка HTTP-уровня. Соединение прошло, сервер ответил, но
КодСостоянияне 2xx: 400 — плохое тело, 401 — авторизация, 403 — права, 404 — путь, 415 — Content-Type, 500 — сервер упал. Исключения нет,HTTPОтветесть, и вся диагностика — в его теле и заголовках.
Правильный код обрабатывает обе ветки:
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
// Ветка 1: соединение не удалось — SSL, DNS, таймаут, прокси
ЗаписьЖурналаРегистрации(
"Интеграция.POST",
УровеньЖурналаРегистрации.Ошибка,
, ,
"Не удалось выполнить POST: " + ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
Если Ответ.КодСостояния < 200 ИЛИ Ответ.КодСостояния >= 300 Тогда
// Ветка 2: сервер ответил, но с ошибкой
ТелоОтвета = Ответ.ПолучитьТелоКакСтроку("UTF-8");
ЗаписьЖурналаРегистрации(
"Интеграция.POST",
УровеньЖурналаРегистрации.Ошибка,
, ,
"HTTP " + Ответ.КодСостояния + ": " + ТелоОтвета);
КонецЕсли;
Ошибка соединения: SSL, «невосстановимая ошибка POST к ресурсу», таймаут
Классический текст исключения в 1С — «Невосстановимая ошибка при выполнении POST к ресурсу /...». Он означает, что до сервера дозвониться не удалось. Причины по частоте:
-
HTTPS без
ЗащищенноеСоединениеOpenSSL. Самая частая причина. При работе сhttps://обязательно передавать объект защиты в конструкторHTTPСоединение, иначе платформа не сможет провести TLS-рукопожатие. - Таймаут. Сервер долго отвечает — соединение обрывается по умолчанию. Явно задавайте таймаут в конструкторе.
- Сертификат. Самоподписанный сертификат сервера или устаревший корневой — платформа отклоняет соединение.
- DNS и прокси. Имя не резолвится с сервера 1С, либо корпоративный прокси не пускает исходящий HTTPS.
ЗащитаHTTPS = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение(
"api.example.com", // Сервер (без https:// и без пути)
443, // Порт
, // Пользователь (для Basic Auth)
, // Пароль
, // Прокси
60, // Таймаут, сек
ЗащитаHTTPS); // ЗащищенноеСоединение
telnet api.example.com 443
прямо с машины, где живёт кластер 1С.
Как корректно отправить POST-запрос в 1С
Половина ошибок «1с ошибка выполнении post запроса» — от неправильного формирования самого запроса. Правильный шаблон для JSON:
Запрос = Новый HTTPЗапрос("/api/v1/documents");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.Заголовки.Вставить("Accept", "application/json");
Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
// ВАЖНО: третий параметр = Ложь → без BOM. Многие сервера падают с 400 из-за BOM.
Запрос.УстановитьТелоИзСтроки(ТелоJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Content-Length платформа считает сама из тела — руками его выставлять не нужно
и вредно (частая причина 400). Если сервер требует form-urlencoded — заголовок
ставится application/x-www-form-urlencoded, а тело формируется
как строка key=value&key2=value2 с URL-кодированием значений.
Ошибка 400 Bad Request: тело, JSON и BOM
Код 400 означает: сервер получил запрос, разобрал заголовки, но не смог обработать тело. В 90% случаев причина — на стороне 1С.
-
Невалидный JSON. Собран строкой вручную, потерялась запятая,
лишний trailing comma, незакрытая скобка. Всегда собирайте JSON через
ЗаписьJSONиЗаписатьJSON(), не через конкатенацию строк. -
ByteOrderMark в начале тела. Если написать
УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8)без третьего параметра, платформа добавит BOM (символ\uFEFF), и строгий парсер JSON на сервере ответит 400. Всегда передавайтеИспользованиеByteOrderMark.НеИспользовать. -
Не заполнены обязательные поля. Сервер ждёт
customer_id, а его в теле нет. Читайте документацию API и смотрите тело ответа — часто там JSON с точным списком ошибок валидации. -
Неправильная кодировка. Кириллица без указания
КодировкаТекста.UTF8уходит в ANSI и превращается в мусор.
// Пример: сборка JSON без BOM и без ручной конкатенации
ПотокЗаписи = Новый ЗаписьJSON;
ПотокЗаписи.УстановитьСтроку();
Данные = Новый Структура("customer_id, amount, currency", 12345, 100.50, "RUB");
ЗаписатьJSON(ПотокЗаписи, Данные);
ТелоJSON = ПотокЗаписи.Закрыть();
Запрос.УстановитьТелоИзСтроки(
ТелоJSON,
КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Ошибки 401 и 403: авторизация и права
Внешне похожи, чинятся по-разному.
-
401 Unauthorized — сервер не понял, кто вы. Не передан заголовок
Authorization, истёк Bearer-токен, неверный логин/пароль для Basic Auth, не подписан запрос там, где нужна HMAC-подпись. - 403 Forbidden — сервер вас узнал, но эта учётка не имеет прав на этот ресурс. IP не в whitelist, роль без разрешения, ограничение по региону/сегменту.
// Bearer-токен: правильно продлевать при 401 и повторять запрос
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 401 Тогда
Токен = ПолучитьНовыйТокен(); // ваша функция обновления
Запрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
КонецЕсли;
// Basic Auth задаётся не заголовком, а в конструкторе HTTPСоединение:
Соединение = Новый HTTPСоединение("api.example.com", 443, "login", "password", , 60, ЗащитаHTTPS);
Для Basic Auth заголовок Authorization: Basic ... платформа формирует
сама, если переданы Пользователь и Пароль в конструктор.
Дублировать его руками не нужно.
Ошибки 404 и 415: путь и Content-Type
-
404 Not Found — сервер не нашёл ресурс по указанному пути.
В
HTTPЗапрос("/api/v1/documents")должен быть только путь, безhttps://api.example.comв начале. Хост уже задан вHTTPСоединение. Второй частый повод — API-версия: путь/api/v1/...заменили на/api/v2/.... -
415 Unsupported Media Type — не подходит заголовок
Content-Type. Отправили JSON безapplication/json, или form-urlencoded с указанием JSON. Проверяйте документацию API: некоторые сервера ждут строгоapplication/json; charset=utf-8, а вариантуtext/jsonотвечают 415.
// Разделение хоста и пути — типовая ошибка
Соединение = Новый HTTPСоединение("api.example.com", 443, , , , 60, ЗащитаHTTPS);
Запрос = Новый HTTPЗапрос("/api/v1/documents"); // Правильно
// Запрос = Новый HTTPЗапрос("https://api.example.com/api/v1/documents"); // 404 или ошибка соединения
Ошибка 500 Internal Server Error: не наша вина, но логируем
Код 500 означает, что сервер упал на своей стороне при обработке нашего запроса. Это не ошибка 1С, но:
- Тело ответа при 500 часто содержит текст исключения или его хеш — обязательно логируйте его целиком в журнал регистрации, иначе разработчику API нечего искать в своих логах.
- На 5xx имеет смысл сделать ретрай с задержкой — сервер мог временно упасть или уйти на рестарт. 4xx повторять бессмысленно: ответ не изменится, пока не поправите запрос.
МаксимумПопыток = 3;
Задержка = 2; // секунды
Для Попытка = 1 По МаксимумПопыток Цикл
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния >= 200 И Ответ.КодСостояния < 300 Тогда
Прервать; // успех
ИначеЕсли Ответ.КодСостояния >= 500 И Попытка < МаксимумПопыток Тогда
// ретрай только для 5xx
ЗаписьЖурналаРегистрации(
"Интеграция.POST",
УровеньЖурналаРегистрации.Предупреждение, , ,
"HTTP " + Ответ.КодСостояния + ", попытка " + Попытка);
// экспоненциальная задержка: 2, 4, 8 секунд
Приостановить(Задержка * Попытка * 1000);
Иначе
Прервать; // 4xx или последняя попытка — выходим
КонецЕсли;
КонецЦикла;
Idempotency-Key). Иначе повторная отправка может создать дубль
документа на стороне контрагента.
Чтение тела ответа, Cookie и сессии
Без чтения тела ответа диагностировать ошибку POST в 1С невозможно — вы работаете
вслепую. Тело читается через ПолучитьТелоКакСтроку() объекта
HTTPОтвет, кодировку берут из заголовка Content-Type
ответа (обычно UTF-8, иногда windows-1251 — в этом случае так и
передавайте, иначе получите кракозябры вместо сообщения об ошибке).
ТелоОтвета = Ответ.ПолучитьТелоКакСтроку("UTF-8");
СерверскийТрейс = Ответ.Заголовки.Получить("X-Request-Id");
ЗаписьЖурналаРегистрации(
"Интеграция.POST",
УровеньЖурналаРегистрации.Ошибка, , ,
"HTTP " + Ответ.КодСостояния + " | X-Request-Id: " + СерверскийТрейс + Символы.ПС + ТелоОтвета);
Некоторые API требуют сначала авторизоваться через POST /login, получить
Set-Cookie, и все последующие POST-запросы отправлять с этим Cookie.
Платформа 1С Cookie сама не хранит между вызовами
ОтправитьДляОбработки() — их нужно доставать из заголовков ответа и
подставлять в заголовки следующего запроса вручную.
Некоторые API требуют сначала авторизоваться через POST /login, получить
Set-Cookie, и все последующие POST-запросы отправлять с этим Cookie.
Платформа 1С Cookie сама не хранит между вызовами
ОтправитьДляОбработки() — их нужно доставать из заголовков ответа и
подставлять в заголовки следующего запроса вручную.
// Первый POST: авторизация, забираем Cookie
ОтветЛогин = Соединение.ОтправитьДляОбработки(ЗапросЛогин);
Кука = ОтветЛогин.Заголовки.Получить("Set-Cookie");
Если Кука <> Неопределено Тогда
// Отрезаем всё после ";" — атрибуты Path/Expires серверу отправлять не нужно
Позиция = СтрНайти(Кука, ";");
Если Позиция > 0 Тогда
Кука = Лев(Кука, Позиция - 1);
КонецЕсли;
ЗапросДанных.Заголовки.Вставить("Cookie", Кука);
КонецЕсли;
// Второй POST: с сохранённой Cookie
ОтветДанные = Соединение.ОтправитьДляОбработки(ЗапросДанных);
Частые ошибки при отправке POST-запроса в 1С
-
HTTPS без ЗащищенноеСоединениеOpenSSL. Первая причина
«невосстановимой ошибки POST к ресурсу». Всегда создавайте
Новый ЗащищенноеСоединениеOpenSSLи передавайте в конструктор. -
Схема в адресе ресурса. В
HTTPЗапрос(...)должен быть только путь —"/api/v1/orders", а не"https://host/api/v1/orders". Иначе 404 или ошибка соединения. -
BOM в теле JSON. Без третьего параметра
УстановитьТелоИзСтроки()добавляет BOM и получает 400. ВсегдаИспользованиеByteOrderMark.НеИспользовать. -
Игнорирование тела ответа при ошибке. Проверяете только
КодСостоянияи не логируетеПолучитьТелоКакСтроку()— теряете точное сообщение сервера и разбираетесь наугад. - Ретрай на 4xx. 401, 403, 404, 415 повторять бессмысленно — ответ не изменится. Ретраить нужно только 5xx и таймауты.
-
Basic Auth дублируется заголовком. Если пользователь и пароль
переданы в конструктор
HTTPСоединение, ставитьAuthorization: Basic ...руками не нужно — платформа сделает это сама. -
Отсутствие Попытка/Исключение. Сетевые ошибки — норма, а не
аварийная ситуация. Без
Попытка/Исключение/ОписаниеОшибки()интеграция валит регламентное задание целиком при любом сетевом сбое.
Быстрый чек-лист, когда ошибка уже произошла и надо найти причину за 5 минут:
- Отделить исключение (соединение не удалось) от кода состояния (сервер ответил).
- Для https — есть ли
ЗащищенноеСоединениеOpenSSLв конструкторе? - В
HTTPЗапрос()передан путь, а не полный URL? - Заголовок
Content-Typeточно соответствует ожиданиям API? - Тело собрано без BOM (
ИспользованиеByteOrderMark.НеИспользовать)? - Авторизация: токен свежий, Basic Auth не дублируется в заголовке?
- Логируется ли тело ответа при не-2xx, есть ли
X-Request-Idв логах? - Для 5xx включён ретрай с задержкой и идемпотентностью?
Частые вопросы об ошибке POST-запроса в 1С
Что значит «Невосстановимая ошибка при выполнении POST к ресурсу» в 1С?
Это исключение платформы: 1С не смогла установить или удержать соединение с сервером.
В 80% случаев причина — HTTPS без объекта ЗащищенноеСоединениеOpenSSL
в конструкторе HTTPСоединение, реже — таймаут, DNS, прокси или закрытый
порт 443 с сервера 1С. Объекта HTTPОтвет в этом случае нет —
диагностика только через ОписаниеОшибки() и журнал регистрации.
Почему сервер отвечает 400 на валидный, на первый взгляд, JSON?
Три классические причины. Первая — BOM в начале тела: происходит при
УстановитьТелоИзСтроки(Тело, КодировкаТекста.UTF8) без третьего
параметра, лечится ИспользованиеByteOrderMark.НеИспользовать.
Вторая — JSON собран конкатенацией строк и содержит невидимую опечатку: используйте
ЗаписьJSON. Третья — не заполнено обязательное поле; читайте тело
ответа через Ответ.ПолучитьТелоКакСтроку("UTF-8"), там обычно
указан точный список ошибок валидации.
Как правильно ретраить POST при ошибке 500 в 1С?
Повторять только коды 5xx и сетевые исключения, а 4xx — никогда. Между попытками
— экспоненциальная задержка (2, 4, 8 секунд), не более 3–5 попыток. Если API не
идемпотентен, добавляйте заголовок Idempotency-Key с уникальным
ключом операции, иначе повтор может создать дубль документа у контрагента.