При разработке интеграций между системами на платформе 1С:Предприятие через HTTP-сервисы разработчики часто сталкиваются с ситуацией, когда серверная часть возвращает ошибку с кодом 500 Internal Server Error, но вызывающая сторона (клиент) получает код 502 Bad Gateway. При этом вместо ожидаемого описания ошибки в теле ответа приходит невнятный набор системных данных или пустая строка. Разберем подробно, почему так происходит, и как правильно транслировать ошибки между системами.
Проанализируем механику работы протокола HTTP. Когда мы используем стандартный конструктор объекта HTTPСервисОтвет, мы передаем три параметра: код состояния, причину и заголовки. Рассмотрим типичную ошибку в коде:
Ответ = Новый HTTPСервисОтвет(500, "Ошибка выполнения: Описание с переносом строки или спецсимволами", Заголовки);
Выясним причину, по которой этот код ломает ответ. Согласно спецификациям RFC, заголовки HTTP (включая статусную строку) являются текстовым протоколом, где в качестве разделителей используются символы \r\n (возврат каретки и перевод строки). Если в параметр Причина (Reason Phrase) попадает текст с переносом строки, кавычками или кириллическими символами, которые веб-сервер (например, IIS или Apache) не может корректно обработать, происходит нарушение структуры пакета.
В этом случае веб-сервер или прокси-сервер (Nginx), стоящий перед 1С, считает, что расширение (модуль 1С) выдало некорректный «битый» ответ. Поскольку прокси-сервер не может распарсить такой заголовок, он обрывает соединение и возвращает клиенту стандартную ошибку 502 Bad Gateway (Плохой шлюз). Таким образом, реальная ошибка 500 от 1С «маскируется» системной ошибкой веб-сервера.
Посмотрим на поле Причина в конструкторе HTTPСервисОтвет. Оно предназначено для краткого стандартного пояснения кода (например, «Internal Server Error» для 500 или «Not Found» для 404). Попытка засунуть туда детальный лог ошибки — плохая практика по нескольким причинам:
Рассмотрим правильный подход к передаче информации об ошибке. Вместо того чтобы пытаться использовать заголовки, мы должны поместить детальное описание ошибки в тело ответа. Проанализируем пример корректной реализации метода сервиса:
Функция ИмяМетодаGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Попытка
// Логика работы сервиса
// ...
Исключение
// Ошибка произошла, формируем ответ 500
Ответ = Новый HTTPСервисОтвет(500);
// Структура для возврата ошибки
ДанныеОшибки = Новый Структура;
ДанныеОшибки.Вставить("Успех", Ложь);
ДанныеОшибки.Вставить("Сообщение", КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
ДанныеОшибки.Вставить("КодОшибки", "ERR_001");
// Преобразуем в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеОшибки);
ТекстОшибкиJSON = ЗаписьJSON.Закрыть();
// Устанавливаем тело ответа и заголовок контента
Ответ.УстановитьТелоИзСтроки(ТекстОшибкиJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
КонецПопытки;
Возврат Ответ;
КонецФункции
В данном примере мы оставляем поле Причина пустым (платформа подставит стандартное значение автоматически) и используем метод УстановитьТелоИзСтроки(). Это гарантирует, что вызывающая система получит именно код 500 и сможет прочитать структурированный JSON с описанием проблемы.
Проанализируем ситуацию, когда даже при пустой «Причине» IIS все равно подменяет ответ. Это часто происходит из-за внутренней настройки обработки ошибок. В веб-сервере IIS есть механизм, который перехватывает ответы с кодами ошибок (4xx, 5xx) и заменяет их своими «красивыми» страницами. Если при этой замене происходит сбой, клиент опять же увидит 502.
Чтобы избежать этого, необходимо настроить файл web.config в каталоге публикации базы 1С. Разберем, какой параметр за это отвечает. В секции <system.webServer> должен присутствовать тег httpErrors с атрибутом existingResponse="PassThrough". Это заставит IIS пропускать ответ от 1С «как есть», не пытаясь его модифицировать.
Подведем итоги нашего исследования. Для стабильной работы ваших интеграций придерживайтесь следующих правил:
UTF-8 при вызове УстановитьТелоИзСтроки() и прописывайте Content-Type в заголовках.HTTP-сервиса в блок Попытка...Исключение. Если в коде произойдет необработанная ошибка, платформа сама сформирует ответ 500, но вы не сможете контролировать его содержимое, что опять же может привести к непредсказуемому результату на стороне веб-сервера.Соблюдение этих правил позволит вам избежать «загадочных» превращений кодов ответов и сделает отладку взаимодействия систем прозрачной и понятной.