Обмен с 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 Картинка УстановитьТелоИзДвоичныхДанных Поток

См. также

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

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

36000 руб.

03.08.2020    17782    19    22    

16

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

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

5040 руб.

04.05.2021    19847    13    17    

16

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    14422    42    8    

18

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

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

24000 руб.

27.09.2024    1172    1    0    

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

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

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

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

HTTPЗапрос.Заголовки.Вставить("Content-Length", XMLСтрока(ДанныеТела.Размер()));
11. ix5s 133 08.09.21 08:46 Сейчас в теме
(10)Спасибо, добавлю в статью если не против, вроде тоже на 8.3.17, скорее всего дело в стороннем сервисе
12. Поручик 4692 08.09.21 09:50 Сейчас в теме
Еще в 2018 году делал передачу файла через тело запроса.
13. Поручик 4692 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 133 08.09.21 12:28 Сейчас в теме
(13)Да все один в один, не видел вашего кода, на сайте ИТС есть статья как отправлять данные, составные, текст, файл, картинка. Я больше хотел показать по структуре самого тела, что служебные символы очень сильно влияют (на чем собственно и застрял, с ответом 400 от сервиса) и о том что через постман можно получить структуру и ее 1 в 1 надо повторить в 1С, возможно с отладочным кодом когда тело в txt и глазами просматривать каждый символ
16. triviumfan 97 13.09.21 09:27 Сейчас в теме
(13)
Content-Length
Разве ты его верно рассчитал?)
17. Поручик 4692 13.09.21 09:30 Сейчас в теме
(16) Это кусок кода из успешно работающей года два фичи. Данные передаются в один госконторский сервис.
Значит, верно.
18. triviumfan 97 13.09.21 09:50 Сейчас в теме
(17)
Это кусок кода из успешно работающей года два фичи. Данные передаются в один госконторский сервис.
Значит, верно

Ничего не значит. http-отладчиком проверял?
14. malikov_pro 1324 08.09.21 11:15 Сейчас в теме
(13) Она в комменте была, на сколько помню, использовал в своих проектах, здесь в виде статьи оформлено.
19. Aleskey_K 35 14.09.21 21:08 Сейчас в теме
20. SpaceOfMyHead 196 15.09.21 23:23 Сейчас в теме
Тоже реализовал через поток в памяти. Статья.
21. broo 6 17.09.21 17:00 Сейчас в теме
Спасибо за статью - очень выручило!
22. Global__IT 309 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 минут, а потом нельзя)
AlisultanovZakir; kild; CratosX; Трактор; +4 Ответить
26. ix5s 133 24.01.22 17:40 Сейчас в теме
Оказывается не так то и мало где применяется русский. В нашем мире английский редкость. =)
alexvbard; tosha_n; +2 Ответить
Оставьте свое сообщение