Интеграция 1С с популярными мессенджерами — одна из наиболее частых задач автоматизации бизнеса. Отправка счетов, актов, расходных накладных и печатных форм напрямую в WhatsApp значительно ускоряет документооборот. Однако при попытке отправить файл в формате PDF разработчики часто сталкиваются с ошибкой сервера HTTP 422 (Unprocessable Entity) и текстом ошибки вида {"status":"ERROR","message":"The string is not valid base64 (body)"}.
В этой статье мы подробно разберем, почему возникает эта ошибка валидации строки Base64, как особенности платформы 1С влияют на кодирование двоичных данных, и как правильно сформировать JSON-пакет для гарантированной доставки файлов через API-шлюзы WhatsApp.
Давайте проанализируем ситуацию. При использовании стандартного метода 1С Base64Строка() (или его современного аналога ПолучитьBase64СтрокуИзДвоичныхДанных()) платформа преобразует бинарный файл в текстовую строку. Однако по умолчанию это преобразование происходит в соответствии со спецификацией MIME (RFC 2045).
Согласно этому стандарту, кодируемый текст должен разбиваться на строки фиксированной длины (обычно 72 или 76 символов). Чтобы выполнить это разбиение, платформа автоматически вставляет в полученную строку невидимые управляющие символы:
Для платформы 1С и некоторых локальных декодеров такая строка остается валидной. Но современные Web-сервисы, API-шлюзы и парсеры на стороне серверов WhatsApp ожидают получить Base64 в виде одной сплошной непрерывной строки без каких-либо служебных переносов. Наличие спецсимволов CRLF приводит к сбою валидации на веб-сервере, и мы получаем ошибку 422.
Выяснив причину проблемы, мы можем легко устранить ее. Для этого достаточно принудительно удалить все символы перевода строк и возврата каретки из полученной Base64-строки. Выполним это с помощью функции СтрЗаменить().
Важно удалять оба спецсимвола, так как на разных операционных системах и в разных контекстах они могут комбинироваться по-разному. Посмотрим на пример кода:
// Получаем чистую Base64-строку без переносов
СтрокаBase64 = Base64Строка(ДвоичныеДанныеФайла);
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ПС, "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ВК, "");
После этой несложной операции наша строка превратится в единый непрерывный массив символов, который без проблем пройдет проверку любым веб-валидатором.
Для того чтобы принимающий веб-сервис и сам клиент WhatsApp поняли, какой тип файла им передается, стандартной Base64-строки бывает недостаточно. Если передать просто набор закодированных символов, принимающая сторона не сможет определить расширение файла (будь то картинка, PDF или текстовый документ).
Для решения этой проблемы большинство API-интеграторов используют схему Data URI. Перед очищенной строкой Base64 необходимо добавить специальную маску-префикс, определяющую MIME-тип документа.
Для PDF-файлов этот префикс выглядит следующим образом:
data:application/pdf;base64,
Для картинок формата JPEG префикс будет другим:
data:image/jpeg;base64,
Посмотрим, как правильно собрать итоговое значение для параметра body в нашем коде:
ПрефиксMime = "data:application/pdf;base64,";
ИтоговыйБоди = ПрефиксMime + СтрокаBase64;
В процессе подготовки параметров запроса нам обязательно нужно передать имя отправляемого файла. Часто разработчики пишут сложные циклы для парсинга полного пути к файлу и поиска символа обратного слэша. Рассмотрим более простой, быстрый и элегантный способ получения имени файла с помощью стандартного объекта Файл:
// Вместо ручного поиска символов "\" в пути к файлу
ОбъектФайл = Новый Файл(ПутьКФайлу);
ИмяФайла = ОбъектФайл.Имя; // Получаем "ИмяФайла.pdf"
Этот метод работает надежно, независимо от того, под какой операционной системой (Windows или Linux) запущен сервер 1С.
Частой ошибкой при формировании JSON-пакетов является попытка «ручной сборки» строки с помощью пошаговой записи через методы ЗаписатьНачалоОбъекта(), ЗаписатьИмяСвойства() и так далее. Ручной метод перегружает код, усложняет чтение и отладку, а также может привести к синтаксическим ошибкам или проблемам с экранированием спецсимволов.
Мы рекомендуем использовать встроенный механизм сериализации 1С. Для этого мы сначала конструируем структуру данных (или массив структур, если этого требует спецификация API), а затем преобразуем ее в JSON одной командой ЗаписатьJSON(). Платформа 1С самостоятельно позаботится о правильном экранировании кавычек, слэшей и кодировании спецсимволов.
Проанализируем готовый пример правильного формирования JSON-пакета:
// Создаем структуру с параметрами запроса
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("chatId", НомерТелефонаПолучателя);
ПараметрыЗапроса.Вставить("body", ИтоговыйБоди);
ПараметрыЗапроса.Вставить("filename", ИмяФайла);
// Если API требует передавать массив объектов (как в некоторых интеграциях)
МассивЗапроса = Новый Массив;
МассивЗапроса.Добавить(ПараметрыЗапроса);
// Сериализуем структуру/массив в формат JSON
ЗаписьJSON = Новый ЗаписьJSON();
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, МассивЗапроса); // или просто ПараметрыЗапроса, в зависимости от API
СтрокаJSON = ЗаписьJSON.Закрыть();
Теперь объединим все наши шаги в один готовый, структурированный и рабочий модуль на языке 1С. Этот шаблон вы можете использовать в своих обработках или регламентных заданиях для отправки печатных форм в WhatsApp.
// Функция подготавливает JSON-строку для отправки файла в WhatsApp
Функция СформироватьПакетДляОтправкиPDF(ТабличныйДокумент, НомерТелефона) Экспорт
// 1. Сохраняем табличный документ во временный PDF-файл
ПутьКВременномуФайлу = ПолучитьИмяВременногоФайла("pdf");
ТабличныйДокумент.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабличныйДокумент.Записать(ПутьКВременномуФайлу, ТипФайлаТабличногоДокумента.PDF);
// 2. Извлекаем имя файла для передачи в API
ОбъектФайл = Новый Файл(ПутьКВременномуФайлу);
ИмяФайла = ОбъектФайл.Имя;
// 3. Считываем двоичные данные файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКВременномуФайлу);
// 4. Кодируем в Base64 и очищаем от служебных символов CRLF
СтрокаBase64 = Base64Строка(ДвоичныеДанныеФайла);
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ПС, "");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, Символы.ВК, "");
// 5. Формируем тело с MIME-префиксом для PDF
ПрефиксMime = "data:application/pdf;base64,";
ПолеBody = ПрефиксMime + СтрокаBase64;
// 6. Формируем структуру параметров в соответствии с API
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("chatId", СокрЛП(НомерТелефона));
СтруктураДанных.Вставить("body", ПолеBody);
СтруктураДанных.Вставить("filename", ИмяФайла);
// Некоторые шлюзы требуют отправки массива объектов в теле запроса
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СтруктураДанных);
// 7. Сериализуем данные в JSON
ЗаписьJSON = Новый ЗаписьJSON();
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, МассивОбъектов);
РезультатJSON = ЗаписьJSON.Закрыть();
// Удаляем временный файл с диска после использования
Попытка
УдалитьФайлы(ПутьКВременномуФайлу);
Исключение
ЗаписьЖурналаРегистрации("Отправка WhatsApp.Ошибка удаления файла",
УровеньЖурналаРегистрации.Предупреждение,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Возврат РезультатJSON;
КонецФункции
После того как вы получили валидную строку JSON в переменной РезультатJSON, отправьте ее на эндпоинт вашего API-провайдера. Помните, что при отправке POST-запроса обязательно нужно указывать правильный заголовок Content-Type: application/json, чтобы принимающий сервер корректно распарсил тело запроса.
Используя данный подход, вы гарантированно избавитесь от ошибок валидации Base64 строк и обеспечите стабильную отправку ваших счетов и накладных клиентам прямо на мобильные устройства.