Реализация скачивания печатной формы документа через веб-сайт с использованием HTTP-сервиса

04.08.19

Интеграция - WEB-интеграция

В статье показан пример, как реализовать скачивание печатной формы документа клиентом (пользователем) по ссылке на веб-сайте.

Наткнулся на публикацию Табличный документ через HTTP сервис и решил поделиться своим опытом.

У организации есть сайт, на этом сайте у клиентов есть личный кабинет. В нём отображаются данные из 1С об их заказах. Необходимо было добавить ссылку (URL), нажав на которую пользователь смог бы скачать печатную форму своих заказов в формате PDF. Для опытного разработчика 1С, в принципе, задача не представляет особой сложности, но, может, эта статья поможет начинающим программистам или тем, кто только осваивает HTTP-сервисы.

Итак, приступим к реализации. В качестве примера будем использовать конфигурацию "Управление торговлей 11" и возвращать печатную форму документа "Заказ клиента".

Нам необходим HTTP-сервис, который отдаст клиенту печатную форму документа. Назовём этот сервис, например, ПередачаДокументов, в качестве корневого URL используем значение GetDocuments. Также потребуется шаблон URL, назовём его Download. Входящим параметром будет являться уникальный идентификатор документа, печатную форму которого необходимо получить. Итоговый URL для скачивания будет иметь следующий вид: http://<адрес_базы_1с>/hs/GetDocuments/Download/<УникальныйИдентификатор>.

Создадим HTTP-сервис:

Добавим шаблон URL:

В созданный шаблон добавим HTTP-метод GET:

И реализуем обработчик этого метода:

Функция ПолучитьПечатнуюФормуGET(Запрос)
	
	Попытка
		// Получим переданный в HTTP-запросе идентификатор документа.
		Идентификатор = Новый УникальныйИдентификатор(Запрос.ПараметрыURL["Идентификатор"]);
	Исключение
		// Полученный параметр не смогли преобразовать в тип "УникальныйИдентификатор".
		HTTPОтвет = Новый HTTPСервисОтвет(400); // 400 - Bad Request
		HTTPОтвет.УстановитьТелоИзСтроки(НСтр("ru='Передан неверный идентификатор'"));
		Возврат HTTPОтвет;
	КонецПопытки; 
	
	// Найдём документ по полученному идентификатору.
	ДокументСсылка = Документы.ЗаказКлиента.ПолучитьСсылку(Идентификатор);
	
	Если ДокументСсылка.ПолучитьОбъект() = Неопределено Тогда
		// Документ с таким уникальным идентификатором не существует.
		HTTPОтвет = Новый HTTPСервисОтвет(404); // 404 - Not Found
		HTTPОтвет.УстановитьТелоИзСтроки(НСтр("ru='Документ не найден'"));
		Возврат HTTPОтвет;
	КонецЕсли; 
	
	#Область ФормированиеПечатнойФормыДокумента
	
	МассивОбъектов = Новый Массив;
	МассивОбъектов.Добавить(ДокументСсылка);
	
	СтруктураТипов = ОбщегоНазначенияУТ.СоответствиеМассивовПоТипамОбъектов(МассивОбъектов);
	ОбъектыПечати = Новый Структура;
	ПараметрыПечати = Неопределено;
	
	// Вызов типовой процедуры печати документа.
	ТабличныйДокумент = Обработки.ПечатьЗаказовНаТоварыУслуги.СформироватьПечатнуюФормуЗаказаКлиента(
		СтруктураТипов, ОбъектыПечати, ПараметрыПечати);
		
	// Запишем табличный документ в поток в памяти в формате PDF.
	Поток = Новый ПотокВПамяти;
	ТабличныйДокумент.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
	
	// Получим двоичные данные для отправки клиенту
	ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
	
	#КонецОбласти 
	
	#Область ОтправкаОтветаКлиенту
	
	// Сформируем имя файла, с которым печатная форма будет загружена у клиента.
	ИмяФайла = Строка(ДокументСсылка) + ".pdf";
	// Кодируем строку URL, чтобы избежать проблем с русскими буквами и другими символами (например, пробел).
	ИмяФайла = КодироватьСтроку(ИмяФайла, СпособКодированияСтроки.КодировкаURL);
	
	// Создадим ответ.
	HTTPОтвет = Новый HTTPСервисОтвет(200); // 200 - OK
	
	// Установим заголовки.
	HTTPОтвет.Заголовки.Вставить("Content-Type", "application/pdf"); // Чтобы браузер знал, что это PDF
	HTTPОтвет.Заголовки.Вставить("Content-Disposition", "attachment; filename=""" + ИмяФайла + """");
	
	// Телом ответа являются двоичные данные печатной формы.
	HTTPОтвет.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);
	
	// И, наконец, вернём ответ клиенту.
	Возврат HTTPОтвет;
		
	#КонецОбласти 
	
КонецФункции

В коде постарался максимально доступно описать выполняемые действия комментариями. Резюмируем, что делает данный обработчик:

  • производится поиск документа по переданному уникальному идентификатору;
  • вызывается стандартная процедура печати документа (аналогично тому, как если бы пользователь нажал кнопку "Печать" в 1С), результатом является табличный документ;
  • табличный документ записывается в нужном формате (при этом используется поток в памяти, чтобы избежать операций с временными файлами);
  • формируется ответ.

Таким образом, когда клиент в личном кабинете нажимает на ссылку для скачивания печатной формы, его браузер производит загрузку файла из 1С. В каталоге загрузок у клиента появится файл вида "Заказ клиента №00001 от 03.08.2019.pdf".

См. также

Интеграция Альфа Авто 5 / Альфа Авто 6 и AUTOCRM / Инфотек

Сайты и интернет-магазины WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    15748    10    17    

11

Интеграция 1С — Битрикс24. Обмен задачами

Сайты и интернет-магазины Интеграция WEB-интеграция Платформа 1С v8.3 Конфигурации 1cv8 Управленческий учет Платные (руб)

Интеграция 1С и Битрикс24. Разработка имеет двухстороннюю синхронизацию 1С и Битрикс24 задачами. Решение позволяет создавать пользователя в 1С из Битрикс24 и наоборот. Данная разработка технически подходит под все основные конфигурации линейки продуктов 1С:Предприятие 8.3 (8.3.18.1289). При приобретении предоставляется 1 месяц бесплатных обновлений разработки. Доступна демо-версия продукта с подключением Вашего Битрикс24

5040 руб.

04.05.2021    17551    6    15    

13

Интеграция с сервисом vetmanager

WEB-интеграция Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    16360    42    49    

23

[Расширение] БОР-Навигатор.Культура

Зарплата Бюджетный учет WEB-интеграция Обмен с ГосИС Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бюджетный учет Платные (руб)

Расширение конфигурации, включающее в себя объекты, необходимые для подготовки и сдачи отчета "Штатная численность" системы "БОР-Навигатор.Культура" в программе "1С:Зарплата и кадры государственного учреждения", редакция 3.1.

8400 руб.

01.02.2019    25741    9    0    

7

Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС

Обмен с ГосИС WEB-интеграция Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия государственного учреждения 1С:Документооборот 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    88580    160    215    

318
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Поручик 4670 04.08.19 23:47 Сейчас в теме
Мне тоже поможет. С HTTP-сервисами ещё не работал
2. dsdred 3251 05.08.19 07:41 Сейчас в теме
Меня только одно смущает, почему УникальныйИдентификатор не "Параметром Запроса" оформлен?

http://host/base/hs/корневойURL/относительныйURL?ПараметрыЗапроса

Шаблон был бы: /Download

Запрос: http://<адрес_базы_1с>/hs/GetDocuments/Download?UUID=<УникальныйИдентификатор>

А так пример неплохой.

А по хорошему так:
Шаблон был бы: /Download/{ТипДокумента}

Запрос: http://<адрес_базы_1с>/hs/GetDocuments/Download/<ТипДокумента>?UUID=<УникальныйИдентификатор>

Тут подробнее: https://infostart.ru/public/842751/
3. trntv 25 05.08.19 09:03 Сейчас в теме
(2) Почему смущает? Спрашиваю, потому что я бы сделал также. Ну разве что шаблон "Download" слишком обобщающий, но в качестве примера допустим.
4. dsdred 3251 05.08.19 09:17 Сейчас в теме
(3)Потому, что используется метод Get, и в таком виде метод получается не гибкий.
Через параметры можно передавать что угодно Уникальный идентификатор, номер, дату и т.д.

Шаблон: /Download/{ТипДокумента}

Вот что получим:

Поиск по УИ:
Запрос: http://<адрес_базы_1с>/hs/GetDocuments/Download/ЗаказКлиента?UUID=<УникальныйИдентификатор>

Поиск по Коду + Номер
http://<адрес_базы_1с>/hs/GetDocuments/Download/ЗаказКлиента?Number=00000022&Date=22.12.2018

и т.д.

Получается более универсальное решение выйдет, а то что предложено в статье это как бетоном залить насмерть. Да и Download тоже согласен что лишнее тут...

П.С. Я за универсальность решений.
13. ltfriend 954 21.06.21 22:37 Сейчас в теме
(2) Понимаю, что прошло два года, но как то в своё время пропустил комментарии к этой публикации. URL адрес в данном случае условный и используется лишь в качестве примера. Основной смысл статьи - продемонстрировать получение печатной формы и передачу её клиенту в виде двоичных данных, а не как правильно формировать ссылки.
5. androgin 05.08.19 15:18 Сейчас в теме
я вот вообще не сторонник передавать параметры в строке. Уж лучше в тело запроса упаковывать все. Безопаснее
6. dsdred 3251 05.08.19 20:40 Сейчас в теме
(5)Забавно но безопаснее не совсем подходит под описание методов типа Post и подобным методам ;)

Безопасные — это методы, которые могут лишь запросить информацию. Они не могут изменить запрашиваемый ресурс, не могут привести к нежелательным результатам для пользователя, других лиц или сервера.

А вообще, да Post и похожие методы не кешируются в браузере и являются более конфиденциальными.
Вот по сравнению методов писал как то: https://infostart.ru/public/886103/

Картинка ниже, утрировано, но очень наглядно показывает выбор между GET и POST:
It-developer; +1 Ответить
7. androgin 06.08.19 15:12 Сейчас в теме
(6) передавать длинные параметры в строке - это ужасно)))))
8. dsdred 3251 06.08.19 15:17 Сейчас в теме
(7)Никто не заставляет передавать длинные параметры. ;)
Просто надо понимать для чего сервис и какой метод под него нужен.
14. ltfriend 954 21.06.21 22:41 Сейчас в теме
(5) Хоть и с задержкой в 2 года, но, как говорится, лучше поздно, чем никогда. А в чём безопасней? Чем принципиально отличается метод GET от метода POST? В любом случае на сервер передаётся текстовый файл.
Ниже содержимое этого файла для GET и POST запроса.
====================
GET /<Адрес ресурса>/<Идентификатор> HTTP/1.1
[Заголовки]
====================
POST /<Адрес ресурса> HTTP/1.1
[Заголовки]

<Идентификатор>
====================
p.s. Давно заметил, что многие не понимают базового принципа HTTP запросов. ВСЕГДА передаётся просто текстовый файл сформированный по определённому формату. И для безопасности неважно адрес будет находиться в первой (стартовой) строке этого файла или в конце этого файла (в так называемом теле запроса, отделённом от заголовков пустой строкой). Хотите безопасности (чтобы нельзя было прочитать содержимое запроса) - HTTPS вам в помощь.
9. info1i 223 04.01.20 02:40 Сейчас в теме
Замечательный код, особенно передача ТабДок через ПотокВПамяти как избавление от нагрузки на диск.
10. user1174740 22.03.20 21:24 Сейчас в теме
Спасибо Вам большое за статью! Вы очень помогли!
11. OlegSemenov2005 21.06.21 20:44 Сейчас в теме
Добрый день.
В примере отправка одного файла, а как отправить несколько?
Не будешь же дергать запросами по одному документу.
12. ltfriend 954 21.06.21 22:29 Сейчас в теме
(11) Здравствуйте. Как вариант, упаковать несколько печ. форм на сервере в архив и отдать его клиенту. Т.е. на вход принимает несколько идентификаторов документов, сохраняем их во временные файлы, эти файлы упаковываем в архив так же в виде временного файла и отдаём этот файл клиенту.
16. AlexVorDOOM 31.08.21 19:45 Сейчас в теме
(12) А нельзя отдавать все эти формы не в архиве а в одном pdf?
15. OlegSemenov2005 22.06.21 08:53 Сейчас в теме
(12) Ответ должен содержать не только файлы, но и некоторое текстовое описания по каждому документу, а так же сам идентификатор документа для обработки его на стороне отправителя. Это уже структура получается.
Сделал массив структур, куда поместил по каждому документу сопроводительные текстовые поля плюс разные печатные формы документа (до 2-х шт. на документ), в двоичных данных. Только ответ представлен как ""Content-Type", "application/json"", а не "pdf".
При обработке ответа двоичные данные печатных форм получается сохранить как файл pdf, но не получается загрузить в табличный документ (ни из потока, ни из сохраненного файла) - "Ошибка при вызове метода контекста (Прочитать): Ошибка при выполнении файловой операции" (ТабличныйДокумент.Прочитать(Поток);).
17. glek 119 25.11.21 07:17 Сейчас в теме
Я бы тут добавил вот еще что (в связке с разработчиком, который ведет сайт, конечно): если пользователь будет ждать когда сформируется документ/отчет, то это не очень хорошо. Как мы сделали у себя:
1. Пользователь запрашивает печатную форму.
2. На стороне 1С формируется идентификатор задания, который сразу возвращается на сайт
3. Одновременно с этим
3.1 формируется запись в регистр сведений с указанным идентификатором, статусом и пустой печатной формой.
3.2 запускается фоновое задание, которое собственно и формирует печатную форму и помещает результат в указанный выше регистр сведений.
4. Сайт опрашивает 1С с указанным заданием и как только форма сформирована, отправляет ответ на сайт в виде (как указано в статье) двоичных данных.
18. Innuil 07.06.22 17:56 Сейчас в теме
Ещё стоит добавить:
	ТабличныйДокумент.Вывод	= ИспользованиеВывода.Разрешить;



У меня ругался на вывод, пока принудительно не прописал.
Оставьте свое сообщение