Работа с внешними веб-сервисами — это стандартная задача для современного разработчика 1С, для упрощения которой часто используют инструменты для тестирования API. Однако при получении файлов, таких как этикетки или печатные формы в формате PDF, часто возникают трудности: файл скачивается, но не открывается, либо имеет подозрительно малый размер. В этой статье мы подробно разберем причины таких ошибок и рассмотрим правильные методы работы с двоичными данными.
Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики. При получении URL файла от веб-сервиса, код может выглядеть так:
FilePDF_url = Данные.FilePDF.url;
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
Поток = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьТекста(Поток, КодировкаТекста.UTF8);
ЗаписьТекста.ЗаписатьСтроку(FilePDF_url);
ЗаписьТекста.Закрыть();
ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
ДвоичныеДанные.Записать(ИмяВременногоФайла);
Проанализируем этот фрагмент. Здесь разработчик совершает критическую ошибку: он записывает в файл саму строку адреса (URL), а не содержимое файла, который находится по этому адресу. В результате получается текстовый файл с расширением .pdf, внутри которого просто написана ссылка. Естественно, ни одна программа для чтения PDF не сможет его открыть.
Если ваш файл весит около 1 кб — это первый признак того, что вместо данных в нем записан текст ошибки (JSON) или просто строка URL. При работе с объемными документами может быть полезно решение для сжатия PDF.
Для того чтобы получить реальное содержимое файла по ссылке, нам необходимо инициировать HTTP-запрос к серверу, предварительно выполнив тестирование http сервисов для проверки параметров запроса. Самый надежный и простой способ — сохранить тело ответа напрямую в файл. Разберем по шагам, как это сделать правильно:
HTTPСоединение.Получить, указав путь к временному файлу.
// Определим параметры подключения
// Допустим, URL имеет вид: https://service.com/api/get_label/123.pdf
Сервер = "service.com";
Ресурс = "/api/get_label/123.pdf";
// Настройка защищенного соединения (для https)
Защита = Новый ЗащищенноеСоединениеOpenSSL();
Попытка
Соединение = Новый HTTPСоединение(Сервер, , , , , , Защита);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
// Создаем запрос
ЗапросHTTP = Новый HTTPЗапрос(Ресурс);
// Получаем файл напрямую в локальное хранилище
ОтветHTTP = Соединение.Получить(ЗапросHTTP, ИмяВременногоФайла);
Если ОтветHTTP.КодСостояния = 200 Тогда
Сообщить("Файл успешно получен и сохранен: " + ИмяВременногоФайла);
Иначе
Сообщить("Ошибка сервера: " + ОтветHTTP.КодСостояния);
КонецЕсли;
Исключение
Сообщить("Ошибка связи: " + ОписаниеОшибки());
КонецПопытки;
Использование метода Получить с указанием пути к файлу вторым параметром — это наиболее эффективный способ работы с памятью. 1С не будет загружать весь объем данных в оперативную память, а сразу запишет поток на диск.
Иногда API возвращает не прямую ссылку на файл, а JSON-объект, внутри которого файл закодирован в строку формата Base64. В этом случае алгоритм действий меняется. Нам нужно преобразовать строку обратно в двоичные данные.
Рассмотрим пример обработки такой строки:
// Предположим, мы получили строку Base64 из JSON
СтрокаBase64 = Данные.FilePDF.ContentBase64;
// Проверим и очистим строку, если она содержит префиксы типа "data:application/pdf;base64,"
Если Найти(СтрокаBase64, "base64,") > 0 Тогда
Части = СтрРазделить(СтрокаBase64, "base64,");
СтрокаBase64 = Части[1];
КонецЕсли;
// Преобразование в двоичные данные
ДвоичныеДанные = Base64Значение(СтрокаBase64);
Если ДвоичныеДанные <> Неопределено Тогда
ИмяФайла = ПолучитьИмяВременногоФайла("pdf");
ДвоичныеДанные.Записать(ИмяФайла);
КонецЕсли;
Важный нюанс: Иногда сервисы возвращают некорректно дополненную строку Base64. В стандарте Base64 длина строки должна быть кратна 4. Если это не так, 1С может вернуть Неопределено. В таких случаях можно программно добавить символы заполнения = в конец строки.
Если вы работаете в среде Linux (серверный вариант 1С) или подключаетесь к современным облачным сервисам, вы можете столкнуться с ошибкой проверки сертификата. Выясним причину: 1С может не видеть системные сертификаты. Для стабильной работы рекомендуется явно инициализировать ЗащищенноеСоединениеOpenSSL.
Если сервис внутренний или использует самоподписанный сертификат, можно временно отключить проверку (только для целей отладки!):
// Игнорирование проверки сертификатов (использовать с осторожностью)
Защита = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Новый СертификатыУдостоверяющихЦентровWindows());
// Либо для Linux:
// Защита = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
Проанализируем еще одну частую ситуацию: код состояния 200 (ОК), файл скачан, но весит 1-2 кб и не открывается. Проблема может заключаться в том, что сервер вместо PDF вернул JSON с описанием ошибки, но сохранил HTTP-статус 200.
Перед тем как записывать файл, всегда проверяйте заголовок Content-Type. Это поможет избежать сохранения бесполезных данных:
ТипСодержимого = ОтветHTTP.Заголовки.Получить("Content-Type");
Если ТипСодержимого <> Неопределено И Найти(ТипСодержимого, "application/pdf") = 0 Тогда
// Это не PDF! Попробуем прочитать тело как текст ошибки
ТекстОшибки = ОтветHTTP.ПолучитьТелоКакСтроку();
Сообщить("Сервер вернул текст вместо PDF: " + ТекстОшибки);
КонецЕсли;
Выполнение этих рекомендаций позволит вам создавать надежные интеграции с веб-сервисами, корректно обрабатывать двоичные данные и эффективно управлять ресурсами сервера 1С.