При интеграции 1С с внешними системами (включая Python-коннектор к 1С) через HTTP-сервисы одной из распространенных задач является передача графических данных (фотографий товаров, изображений сотрудников или сканов документов для распознавания). Стандартным способом передачи бинарных данных (который автоматизирует конструктор API) внутри текстового формата JSON является кодирование в Base64. Однако разработчики часто сталкиваются с проблемой: на стороне получателя строка оказывается "битой" или содержит нежелательные символы переноса строк (\n, \r), что мешает корректному декодированию изображения. В этой статье мы подробно разберем, как правильно подготовить картинку, сформировать JSON и избежать типичных ошибок.
Разберем ситуацию: почему при использовании стандартной функции Base64Строка() или библиотеки для работы с двоичными данными в итоговом сообщении появляются переносы? Дело в том, что глобальная функция 1С формирует строку в соответствии со стандартом MIME (RFC 2045). Согласно этому стандарту, для обеспечения совместимости со старыми почтовыми системами, в строку должны вставляться символы разрыва строки через каждые 72 или 76 символов.
Для современного JSON-парсера эти символы являются избыточными, а иногда и недопустимыми, если они не экранированы. Если мы просто вставляем такую строку в структуру и сериализуем её, 1С может добавить экранирование (например, превратить символ переноса в последовательность \n), что увеличит объем данных и может привести к ошибке на принимающей стороне.
Самый простой и надежный способ — это принудительное удаление всех символов переноса строк и возврата каретки сразу после преобразования двоичных данных в строку. Проанализируем пример кода, который позволяет это сделать:
Функция ФотоФизЛицаВBase64(ФайлСсылка)
// Получаем двоичные данные файла
ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(ФайлСсылка);
// Преобразуем в Base64
ФотоBase64 = Base64Строка(ДвоичныеДанные);
// Очищаем строку от переносов (Символы.ПС - \n, Символы.ВК - \r)
ФотоBase64 = СтрЗаменить(ФотоBase64, Символы.ВК, "");
ФотоBase64 = СтрЗаменить(ФотоBase64, Символы.ПС, "");
Возврат ФотоBase64;
КонецФункции
Рассмотрим более продвинутый вариант очистки, который разом удаляет все возможные "мусорные" символы (пробелы, табуляции и переносы), которые могут возникнуть при чтении данных из необычных источников:
// Удаление всех разделителей через разделение и соединение строки
СписокРазделителей = Символы.ПС + Символы.ВК + Символы.Таб + " ";
ЧастиСтроки = СтрРазделить(ФотоBase64, СписокРазделителей, Ложь);
ФотоBase64 = СтрСоединить(ЧастиСтроки, "");
Начиная с версии платформы 8.3.10, у объекта ДвоичныеДанные появился собственный метод для получения Base64. Посмотрим на пример его использования:
ДвоичныеДанныеКартинки = Новый ДвоичныеДанные(ПутьКФайлу);
СтрокаBase64 = ДвоичныеДанныеКартинки.Base64Строка();
Хотя этот метод работает быстрее, важно помнить, что он также может следовать правилам форматирования платформы. Поэтому проверку на наличие переносов строк стоит оставить в любом случае.
Когда строка подготовлена, нам нужно правильно сформировать JSON-ответ. Проанализируем процесс записи JSON с использованием специализированных объектов платформы. Важно правильно установить параметры записи, чтобы избежать двойного экранирования или проблем с кодировкой.
// Создаем объект записи
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
// Формируем структуру данных
ДанныеДляОтправки = Новый Структура;
ДанныеДляОтправки.Вставить("status", "success");
ДанныеДляОтправки.Вставить("photo", ФотоBase64);
// Записываем данные
ЗаписатьJSON(ЗаписьJSON, ДанныеДляОтправки);
ОтветJSON = ЗаписьJSON.Закрыть();
Обратите внимание на параметр ЭкранироватьРазделителиСтрок в настройках ПараметрыЗаписиJSON. Если установить его в значение Истина, платформа будет корректно обрабатывать управляющие символы, если они всё же остались в строке. Однако для чистоты данных лучше передавать строку без них.
Для того чтобы принимающая сторона (браузер, мобильное приложение или другой сервер) правильно интерпретировала полученные данные, необходимо верно указать Content-Type в заголовках ответа HTTP-сервиса. Посмотрим, как это сделать — для отладки и логирования таких запросов пригодится модуль логирования HTTP-запросов и JSON-ответов.
Ответ = Новый HTTPСервисОтвет(200);
// Указываем, что передаем именно JSON, а не обычный текст или HTML
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ОтветJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
Использование application/json вместо text/html является критически важным стандартом для REST-интерфейсов — развернуть готовый обмен поможет готовое решение REST API для интеграции 1С через HTTP-сервисы.
Передача изображений в формате Base64 имеет один существенный недостаток: объем данных увеличивается примерно на 33% по сравнению с исходным бинарным файлом. Рассмотрим, как мы можем оптимизировать этот процесс:
Картинка — для автоматической оптимизации файлов подойдёт обработка сжатия и изменения разрешения изображений.maxAllowedContentLength в конфигурации IIS) позволяет передавать файлы нужного размера.Пример уменьшения картинки перед отправкой:
КартинкаОригинал = Новый Картинка(ПутьКФайлу);
// Допустим, нам нужно превью 200x200
ОбработаннаяКартинка = КартинкаОригинал.Преобразовать(ФорматКартинки.JPEG);
// Здесь можно использовать компоненты для изменения размера
ДвоичныеДанныеДляОтправки = ОбработаннаяКартинка.ПолучитьДвоичныеДанные();
Проанализируем ситуацию, когда передача через Base64 внутри JSON не является обязательной. Если архитектура позволяет, гораздо эффективнее передавать файл напрямую в теле HTTP-ответа. Разберем, как это реализовать:
Content-Type: image/jpeg (или другой соответствующий формат).Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные).Этот метод исключает лишние этапы кодирования/декодирования, экономит память сервера и сокращает время загрузки данных пользователем. Однако он подходит только в том случае, если вам нужно передать один файл за один запрос без сопроводительной текстовой информации в формате JSON.
Таким образом, мы рассмотрели все основные аспекты работы с изображениями в JSON. Помните, что чистота строки Base64 и правильные HTTP-заголовки — залог стабильной работы вашей интеграции.