Обмен с HTTP сервисом файлами по формату multipart/form-data

07.09.21

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

Потребовалось отправить картинку в теле запроса в HTTP сервис методом POST, куча реализаций, но есть маленькие нюансы, если хотя бы кому-то поможет, то уже это было не напрасно.

Все как всегда, легко и просто

Создаем соединение через Новый HTTPСоединение()

Создаем HTTPЗапрос через Новый HTTPЗапрос()

Дальше все кажется логичным и простым

Методом HTTP запроса УстановитьТелоИзДвоичныхДанных() передаем в него картинку и отправляем

Было бы очень легко и интуитивно понятно, но тут начинается веселье, как по мне

Формат multipart/form-data требует очень четкой структуры данных

Через Postman смотрим snippet

// ЗАГОЛОВКИ

Content-Length: 232 // длина сообщения, не обязательна
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW // определение типа данных и указание разделителя

// Тело запроса
----WebKitFormBoundary7MA4YWxkTrZu0gW // разделитель
Content-Disposition: form-data; name="file"; filename="Scan.jpg" // описание поля по формату с указанием имени поля "file" и название данных для принимающей стороны
Content-Type: image/jpeg // тип данных

(data) // сами данные
----WebKitFormBoundary7MA4YWxkTrZu0gW // закрывающий  разделитель

Тоже все понятно и легко вроде как, но я словил так называемую ошибку, над которой даже не задумался

1. Структура должна быть обязательно именно такой, повторяя каждый отступ и перенос

Разделитель, Символ.ВК, Символ.ПС
Описание, Символ.ВК, Символ.ПС
ОписаниеТипа, Символ.ВК, Символ.ПС,
Символ.ВК, Символ.ПС
ДвочныеДанные, Символ.ВК, Вимвол.ПС
Разделитель

2. При записи через поток при определении ЗаписьДанных можно переопределить

РазделительСтрок - Значение по умолчанию: ПС
КонвертируемыйРазделительСтрок - Значение по умолчанию: ВК + ПС

Получается, в мои данные добавлялись лишние символы, помогло сохранение данных из записи данных в файл и просмотр символов.

В итоге код, который отработал, в конечном варианте выглядит вот так: 


КартинкаИмяПараметра = "file";
КартинкаИмяФайла = "Scan.jpg";
Картинка = Новый Картинка(АдресФайла); // любым удобным способом, по факту нужны ДД изображения
// 
Разделитель = СтрЗаменить(Новый УникальныйИдентификатор(), "-", ""); // все что угодно, можно даже руками указать "razzdell", главное что бы оно было уникальное во всем тексте тела

// --Отладочный кусок
// ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // временный файл для сохранения полученного тела для запроса
// ++Отладочный кусок

Тело = Новый ПотокВПамяти();
ЗаписьДанных = Новый ЗаписьДанных(Тело, , , Символы.ВК + Символы.ПС, ""); // то самое переопределение разделителей               
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=" + КартинкаИмяПараметра + "; filename=" + КартинкаИмяФайла);
ЗаписьДанных.ЗаписатьСтроку("Content-Type: image/jpeg");
ЗаписьДанных.ЗаписатьСтроку(""); // пустая строка для доп переноса и воспроизведения структуры тела
ЗаписьДанных.Записать(Картинка.ПолучитьДвоичныеДанные()); // добавляет данные но каретка остается после данных
ЗаписьДанных.ЗаписатьСтроку(""); // записать не добавляет переносов, добавляем их пустой строкой
ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--"); // добавляются еще доп переносы, но они уже не на что не влияют, так же после разделителя добавляем "--", должно обозначать конец тела
ЗаписьДанных.Закрыть();

ДанныеТела = Тело.ЗакрытьИПолучитьДвоичныеДанные(); // получаем дело в дд, можно и через запись в файл, просто лишний раз не трогаем диски и не делаем доп операций

// --Отладочный кусок
//	ДанныеТела.Записать(ИмяВременногоФайла); // записывает ДД в txt файл
// ++Отладочный кусок

HTTPЗапрос.УстановитьТелоИзДвоичныхДанных(ДанныеТела); // установили тело
HTTPЗапрос.Заголовки.Вставить("Content-Length", XMLСтрока(ДанныеТела.Размер()));
HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + разделитель);
ОтветHTTP = Соединение.ОтправитьДляОбработки(HTTPЗапрос); // финал


Если есть возможность улучшить, адаптировать, сделать проще, я только за, жду в комментариях.

Обен POST HTTP Картинка УстановитьТелоИзДвоичныхДанных Поток

См. также

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

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

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

36000 руб.

03.08.2020    15749    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    17556    6    15    

13

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

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

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

12000 руб.

02.02.2021    16362    42    49    

23

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

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

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

8400 руб.

01.02.2019    25746    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    88587    160    215    

318
Отзывы
24. userfirerain 16.01.22 21:39 Сейчас в теме
Блестяще, что все названия переведены на русский! Только учитывая, что такой язык мало где применяется, и почти всегда приходится пока что писать на английском, нельзя ли было в скобках продублировать, как это в стандартной английской Яве звучит? Не всегда легко на лету переводить обратно.
Остальные комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. frkbvfnjh 786 07.09.21 14:44 Сейчас в теме
Как раз искал простой пример кода для отправки запроса в формате multipart/form-data. Спасибо!
sikuda; Serg O.; +2 Ответить
23. igorprokopjuk 05.12.21 16:54 Сейчас в теме
Спасибо за статью, Ваш метод рабочий, мне тоже помогло !
2. frkbvfnjh 786 07.09.21 14:59 Сейчас в теме
4. ix5s 118 07.09.21 15:11 Сейчас в теме
(2) Спасибо
По факту лишние для прода

ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt"); // временный файл для сохранения полученного тела для запроса

Там еще должна была быть строка записи все в txt, сейчас добавлю

ДанныеТела.Записать(ИмяВременногоФайла);
igorprokopjuk; +1 Ответить
3. frkbvfnjh 786 07.09.21 15:03 Сейчас в теме
А можете для наглядности еще привести пример запроса когда нужно отправить например несколько файлов/картинок. В таком случае не совсем понятно как расставить разделители. А еще лучше как слать в перемешку текст с двоичными данными.
5. ix5s 118 07.09.21 15:13 Сейчас в теме
(3)Если есть пример сервиса куда можно закидывать несколько файлов, картинок, можно было бы попробовать расширить, но по факту блок универсален, повторяем все тоже самое без закрывающего разделителя, закрывающий один в самом конце
6. frkbvfnjh 786 07.09.21 15:18 Сейчас в теме
7. Sodrugestvo 07.09.21 18:56 Сейчас в теме
Посмотрите реализацию в библиотеке коннектор
https://github.com/vbondarevsky/Connector
к вопросу улучшить и адаптировать
triviumfan; JohnyDeath; CSiER; +3 Ответить
9. ix5s 118 07.09.21 23:13 Сейчас в теме
(7)спасибо, видел, изучаю, восхищаюсь)
8. пользователь 07.09.21 20:59
Сообщение было скрыто модератором.
...
10. malikov_pro 1292 08.09.21 04:14 Сейчас в теме
"Content-Length: 232 // длина сообщения, не обязательна" - при установке тела через строку некорректно считало длину (8.3.17) из за чего сторонний сервис не мог прочитать данные

HTTPЗапрос.Заголовки.Вставить("Content-Length", XMLСтрока(ДанныеТела.Размер()));
11. ix5s 118 08.09.21 08:46 Сейчас в теме
(10)Спасибо, добавлю в статью если не против, вроде тоже на 8.3.17, скорее всего дело в стороннем сервисе
12. Поручик 4670 08.09.21 09:50 Сейчас в теме
Еще в 2018 году делал передачу файла через тело запроса.
13. Поручик 4670 08.09.21 09:58 Сейчас в теме
Собственно, принцип тот же самый.
		ПотокТело = Новый ПотокВПамяти();
		ЗаписьДанных = Новый ЗаписьДанных(ПотокТело);
		
		ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
		ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""resumableType""");
		ЗаписьДанных.ЗаписатьСтроку("");
		ЗаписьДанных.ЗаписатьСтроку("application/" + ДанныеФайла.Расширение);
		
		ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
		ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" + ИмяФайлаДляЗагрузки + """");
 		ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/x-octet-stream");
		ЗаписьДанных.ЗаписатьСтроку("");
		ЗаписьДанных.Записать(МассивЧастей[НомерЧасти - 1].ПолучитьДвоичныеДанные());
		ЗаписьДанных.ЗаписатьСтроку("");
		
		ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--");
		
		ЗаписьДанных.Закрыть();
		ДвоичныеДанныеТело = ПотокТело.ЗакрытьИПолучитьДвоичныеДанные();
		
		ЗаголовкиHTTP = Новый Соответствие;
		ЗаголовкиHTTP.Вставить("Accept", "*/*");
		ЗаголовкиHTTP.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
		ЗаголовкиHTTP.Вставить("Content-Length", XMLСтрока(ДвоичныеДанныеТело.Размер()));
Показать

Дальше штатный способ
Il; Yashazz; +2 Ответить
15. ix5s 118 08.09.21 12:28 Сейчас в теме
(13)Да все один в один, не видел вашего кода, на сайте ИТС есть статья как отправлять данные, составные, текст, файл, картинка. Я больше хотел показать по структуре самого тела, что служебные символы очень сильно влияют (на чем собственно и застрял, с ответом 400 от сервиса) и о том что через постман можно получить структуру и ее 1 в 1 надо повторить в 1С, возможно с отладочным кодом когда тело в txt и глазами просматривать каждый символ
16. triviumfan 93 13.09.21 09:27 Сейчас в теме
(13)
Content-Length
Разве ты его верно рассчитал?)
17. Поручик 4670 13.09.21 09:30 Сейчас в теме
(16) Это кусок кода из успешно работающей года два фичи. Данные передаются в один госконторский сервис.
Значит, верно.
18. triviumfan 93 13.09.21 09:50 Сейчас в теме
(17)
Это кусок кода из успешно работающей года два фичи. Данные передаются в один госконторский сервис.
Значит, верно

Ничего не значит. http-отладчиком проверял?
14. malikov_pro 1292 08.09.21 11:15 Сейчас в теме
(13) Она в комменте была, на сколько помню, использовал в своих проектах, здесь в виде статьи оформлено.
19. Aleskey_K 32 14.09.21 21:08 Сейчас в теме
20. SpaceOfMyHead 188 15.09.21 23:23 Сейчас в теме
Тоже реализовал через поток в памяти. Статья.
21. broo 6 17.09.21 17:00 Сейчас в теме
Спасибо за статью - очень выручило!
22. Global__IT 264 23.09.21 22:13 Сейчас в теме
Интересно. А я через временные файлы реализовывал. Эта библиотеку пользую уже наверное лет 7. Попробую через ПотокВПамяти
24. userfirerain 16.01.22 21:39 Сейчас в теме
Блестяще, что все названия переведены на русский! Только учитывая, что такой язык мало где применяется, и почти всегда приходится пока что писать на английском, нельзя ли было в скобках продублировать, как это в стандартной английской Яве звучит? Не всегда легко на лету переводить обратно.
25. userfirerain 16.01.22 22:17 Сейчас в теме
(24) блин, я же искал по Яве решения, только после регистрации обнаружил, что это по 1С )
Хотел удалить пост, но обнаружил, что можно его только изменить - хотел изменить, но было написано, что редактировать можно только через 30 минут - как дурак, ждал, пока пройдёт 30 минут - теперь внезапно написано наоборот: редактировать можно только 30 минут, а потом нельзя)
kild; CratosX; Трактор; +3 Ответить
26. ix5s 118 24.01.22 17:40 Сейчас в теме
Оказывается не так то и мало где применяется русский. В нашем мире английский редкость. =)
alexvbard; tosha_n; +2 Ответить
Оставьте свое сообщение