При интеграции систем на платформе 1С с веб-приложениями часто возникает задача передачи данных в формате JSON через HTTP-сервисы. Несмотря на кажущуюся простоту, разработчики часто сталкиваются с неочевидными проблемами: пустой строкой на выходе, некорректным заполнением заголовков ответа, ошибками разбора (парсинга) JSON на клиенте или искажением кодировки веб-сервером. В этой статье мы подробно разберем, как правильно сформировать JSON в кодировке UTF-8, корректно настроить HTTP-ответ и обойти «подводные камни» конфигурации веб-сервера Apache.
Самый простой и распространенный способ передать JSON-структуру клиенту — сформировать ее в виде строки в оперативной памяти 1С. Рассмотрим пошаговый алгоритм реализации этого метода:
ЗаписьJSON и подготавливаем его к записи в строку.ЗаписатьJSON.Проанализируем пример готового кода для HTTP-сервиса:
// Шаг 1. Готовим данные для отправки
СтруктураВывода = Новый Структура;
СтруктураВывода.Вставить("remember", Ложь);
СтруктураВывода.Вставить("status", Истина);
// Шаг 2. Инициализируем запись JSON в строку
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
// Шаг 3. Сериализуем структуру 1С в JSON
ЗаписатьJSON(ЗаписьJSON, СтруктураВывода);
// Шаг 4. Получаем строку и закрываем объект
СтрокаJSON = ЗаписьJSON.Закрыть();
Этот способ идеально подходит для небольших пакетов данных, так как строка целиком размещается в оперативной памяти сервера приложений 1С.
Если объем передаваемых данных велик или требуется оптимизировать работу с памятью, целесообразно использовать потоковую запись через ПотокВПамяти. Распространенной ошибкой разработчиков является попытка получить строку методом ЗаписьJSON.Закрыть() при открытом потоке — в этом случае метод возвращает Неопределено.
Выясним причину: при записи в поток объект ЗаписьJSON сбрасывает данные напрямую в буфер потока, а не накапливает их в строковой переменной платформы. Чтобы корректно получить результат, мы должны проделать следующие действия:
// Создаем поток в памяти
Поток = Новый ПотокВПамяти;
ЗаписьJSON = Новый ЗаписьJSON;
// Открываем поток с явным указанием кодировки UTF-8
ЗаписьJSON.ОткрытьПоток(Поток, "UTF-8");
// Записываем данные в поток
ЗаписатьJSON(ЗаписьJSON, СтруктураВывода);
// Обязательно сначала закрываем ЗаписьJSON, чтобы сбросить буферы в поток
ЗаписьJSON.Закрыть();
// Получаем двоичные данные из потока и закрываем его
ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
// Преобразуем двоичные данные в строку UTF-8
СтрокаJSON = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.UTF8);
Полезный совет по оптимизации: Если вы передаете данные в HTTP-ответ, нет необходимости преобразовывать двоичные данные обратно в строку на стороне 1С. Платформа позволяет передать двоичные данные напрямую в тело HTTP-ответа, что значительно экономит ресурсы процессора и памяти:
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);
Частой ошибкой при создании веб-сервисов является путаница между заголовками (Headers) и телом (Body) HTTP-ответа. Попытки передать JSON-строку в заголовках (например, через Ответ.Заголовки.Вставить("result", СтрокаJSON)) приводят к падению сервиса или некорректной интерпретации ответа клиентом.
Рассмотрим правильный шаблон формирования ответа:
Ответ = Новый HTTPСервисОтвет(200);
// Очищаем заголовки (при необходимости)
Ответ.Заголовки.Очистить();
// Указываем тип контента. Для JSON это строго application/json
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Устанавливаем куки (Cookie), если это требуется для авторизации
ВремяЖизни = "3600"; // Время жизни куки в секундах
Ответ.Заголовки.Вставить("Set-Cookie", "token=" + ТокенПользователя + "; Max-Age=" + ВремяЖизни + "; HttpOnly; SameSite=Lax;");
// Записываем JSON-строку непосредственно в тело ответа
Ответ.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
Обратите внимание на параметр ИспользованиеByteOrderMark.НеИспользовать. Веб-клиенты (особенно JS-парсеры в браузерах) плохо реагируют на наличие BOM (Byte Order Mark) сигнатуры в начале JSON-файла, поэтому его добавление следует отключать.
Иногда код в 1С написан абсолютно верно, заголовки установлены, но при попытке прочитать ответ в JS-коде (например, через $.ajax или fetch) клиент падает с ошибкой синтаксического разбора JSON. При этом в отладчике мы можем видеть кракозябры вместо кириллицы.
Выясним причину этой проблемы. При публикации базы 1С на веб-сервере Apache, последний выступает в роли прокси-сервера. Если в конфигурационном файле Apache (httpd.conf) включена принудительная кодировка по умолчанию, веб-сервер переопределит заголовки 1С и отдаст текстовые данные в неверной кодировке.
Проанализируем, как решить эту проблему в настройках Apache:
httpd.conf в папке conf установленного сервера).AddDefaultCharset.AddDefaultCharset windows-1251), это и является причиной искажения данных.
AddDefaultCharset Off
Или явно укажите использование UTF-8 в качестве глобального стандарта:
AddDefaultCharset UTF-8
Существует заблуждение, что метод GET в HTTP-сервисах 1С не умеет работать с форматом JSON. Это не так. Ограничение касается только передачи данных от клиента к серверу 1С:
/hs/my_service/auth?login=admin&remember=true. При этом возвращать JSON-ответ из 1С в методе GET можно абсолютно свободно.Запрос.ПолучитьТелоКакСтроку("UTF-8").Применяя данные подходы, вы сможете выстроить стабильный и отказоустойчивый обмен данными между вашей базой 1С и внешними веб-приложениями.