Как правильно получить и сохранить PDF-файл через API в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с внешними веб-сервисами — это стандартная задача для современного разработчика 1С, для упрощения которой часто используют инструменты для тестирования API. Однако при получении файлов, таких как этикетки или печатные формы в формате PDF, часто возникают трудности: файл скачивается, но не открывается, либо имеет подозрительно малый размер. В этой статье мы подробно разберем причины таких ошибок и рассмотрим правильные методы работы с двоичными данными.

Анализ типичной ошибки: почему PDF не открывается?

Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики. При получении URL файла от веб-сервиса, код может выглядеть так:


FilePDF_url = Данные.FilePDF.url;
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
Поток = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьТекста(Поток, КодировкаТекста.UTF8);
ЗаписьТекста.ЗаписатьСтроку(FilePDF_url);
ЗаписьТекста.Закрыть();
ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
ДвоичныеДанные.Записать(ИмяВременногоФайла);

Проанализируем этот фрагмент. Здесь разработчик совершает критическую ошибку: он записывает в файл саму строку адреса (URL), а не содержимое файла, который находится по этому адресу. В результате получается текстовый файл с расширением .pdf, внутри которого просто написана ссылка. Естественно, ни одна программа для чтения PDF не сможет его открыть.

Если ваш файл весит около 1 кб — это первый признак того, что вместо данных в нем записан текст ошибки (JSON) или просто строка URL. При работе с объемными документами может быть полезно решение для сжатия PDF.

Решение №1: Использование HTTP-соединения для скачивания файла

Для того чтобы получить реальное содержимое файла по ссылке, нам необходимо инициировать HTTP-запрос к серверу, предварительно выполнив тестирование http сервисов для проверки параметров запроса. Самый надежный и простой способ — сохранить тело ответа напрямую в файл. Разберем по шагам, как это сделать правильно:

  1. Разделим URL на адрес сервера и путь к ресурсу.
  2. Создадим объект HTTPСоединение.
  3. Выполним метод Получить, указав путь к временному файлу.

// Определим параметры подключения
// Допустим, 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С не будет загружать весь объем данных в оперативную память, а сразу запишет поток на диск.

Решение №2: Работа с Base64 из JSON-ответа

Иногда 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С может вернуть Неопределено. В таких случаях можно программно добавить символы заполнения = в конец строки.

Тонкости настройки защищенного соединения (HTTPS)

Если вы работаете в среде Linux (серверный вариант 1С) или подключаетесь к современным облачным сервисам, вы можете столкнуться с ошибкой проверки сертификата. Выясним причину: 1С может не видеть системные сертификаты. Для стабильной работы рекомендуется явно инициализировать ЗащищенноеСоединениеOpenSSL.

Если сервис внутренний или использует самоподписанный сертификат, можно временно отключить проверку (только для целей отладки!):


// Игнорирование проверки сертификатов (использовать с осторожностью)
Защита = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Новый СертификатыУдостоверяющихЦентровWindows());
// Либо для Linux:
// Защита = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);

Проверка MIME-типа: действительно ли это PDF?

Проанализируем еще одну частую ситуацию: код состояния 200 (ОК), файл скачан, но весит 1-2 кб и не открывается. Проблема может заключаться в том, что сервер вместо PDF вернул JSON с описанием ошибки, но сохранил HTTP-статус 200.

Перед тем как записывать файл, всегда проверяйте заголовок Content-Type. Это поможет избежать сохранения бесполезных данных:


ТипСодержимого = ОтветHTTP.Заголовки.Получить("Content-Type");
Если ТипСодержимого <> Неопределено И Найти(ТипСодержимого, "application/pdf") = 0 Тогда
    // Это не PDF! Попробуем прочитать тело как текст ошибки
    ТекстОшибки = ОтветHTTP.ПолучитьТелоКакСтроку();
    Сообщить("Сервер вернул текст вместо PDF: " + ТекстОшибки);
КонецЕсли;

Выполнение этих рекомендаций позволит вам создавать надежные интеграции с веб-сервисами, корректно обрабатывать двоичные данные и эффективно управлять ресурсами сервера 1С.

← На главную