Отправка файла POST запросом

1. gnp90 16.12.20 15:40 Сейчас в теме
Доброго времени суток, подскажите а то уже всю головку сломал, перепробовал разные внешние комоненты в том числе WinHttp.WinHttpRequest.5.1, ничего не получается, такое ощущение что формат данных для передачи не правильные, сервер ожидает UTF-8. Тот же самый файл, тот же самый запрос отправляется POSTMAN и Python'ом без проблем.

Есть задача, отправить файл по API на сервер POST Запросом.
Выполняю:

ИмяФайлаДляЗагрузки = 1.pdf;
	
	дд = ПолучитьИзВременногоХранилища(Адр);
		
	Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");
	РазделительСтрок = Символ(10)+Символ(13);
			
	Данные = ПолучитьСтрокуИзДвоичныхДанных(дд);

	ЗапросWeb = Новый HTTPЗапрос("/decodefile/");
	ЗапросWeb.Заголовки.Вставить("Content-Type","multipart/form-data; boundary=" + Boundary+"; charset=utf-8");
	ЗапросWeb.Заголовки.Вставить("Accept-Charset", "utf-8");
	ЗапросWeb.Заголовки.Вставить("Content-Charset", "utf-8");
		
	ТелоЗапроса = ЗапросWeb.ПолучитьТелоКакПоток();
	ЗаписьДанных = Новый ЗаписьДанных(ТелоЗапроса, КодировкаТекста.UTF8, ПорядокБайтов.LittleEndian, РазделительСтрок, "", Ложь);
	ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + РазделительСтрок);
	ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
	ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8");

	ЗаписьДанных.Записать(дд);
	ЗаписьДанных.ЗаписатьСтроку(РазделительСтрок);
	ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--" + РазделительСтрок);
	ЗаписьДанных.Закрыть();

	Соединение = Новый HTTPСоединение("10.10.61.30",9990,,,,,,);
	
	ОтветWeb = Соединение.ОтправитьДляОбработки(ЗапросWeb);
	Сообщить(ОтветWeb.КодСостояния);
	ссответа = ОтветWeb.ПолучитьТелоКакСтроку("UTF-8");
	Сообщить(ссответа);
Показать

В ответ приходит:
400
{"detail":"There was an error parsing the body"}
По теме из базы знаний
Найденные решения
12. uno-c 235 16.12.20 21:12 Сейчас в теме
(10) Ну если так уж хочется без готовой библиотеки - то что я заметил:
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + РазделительСтрок);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8");


должно быть
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8"  + РазделительСтрок);


Сам РазделительСтрок не тот 10+13. RFC2045 -
The term CRLF, in this set of documents, refers to the sequence of octets corresponding to the two US-ASCII characters CR (decimal value 13) and LF (decimal value 10)
Т.е. должен быть 13+10.
Вообще когда я файлами мультипарт собирал - получалось, что ему достаточно ПС (10) - хоть и отклоняется от RFC - но проходило.
Ибо я использовал обычную ЗаписьТекста, которая по умолчанию в конце строки ставит только ПС.
ЗаписьТекста = Новый ЗаписьТекста(имяФайлаСПараметрами, "CESU-8"); //utf-8 без bom
// параметр "photo"
ИмяФайла = Строка(Новый УникальныйИдентификатор()) + "." + РасширениеФайлаКартинки;	
ЗаписьТекста.ЗаписатьСтроку("--"+boundary);
ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""photo""; filename=""" + ИмяФайла + """");
ЗаписьТекста.ЗаписатьСтроку("Content-Type: image/"+РасширениеФайлаКартинки);
ЗаписьТекста.ЗаписатьСтроку("");
// дальше присоединялись двоичные данные картинки
Показать
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. Sashares 34 16.12.20 16:42 Сейчас в теме
(1)
подскажите а то уже всю головку сломал, перепробовал разные внешние комоненты в том числе WinHttp.WinHttpRequest.5.1, ничего не получается, такое ощущение что формат данных для передачи не правильные, сервер ожидает UTF-8. Тот же самый файл, тот же самый запрос отправляется POSTMAN и Python'ом без проблем.


Чтобы не гадать, что не так, надо смотреть в чем отличия при правильной отправке и при не правильной.
Это удобно и наглядно можно увидеть с помощью Fiddler'а.
5. gnp90 16.12.20 16:48 Сейчас в теме
(3)Вот скрины запроса который уходит, единственное отличие которое нашёл это отличие кодировки и соответственно размера файла((( Поэтому и решил что кодировка не правильна
Прикрепленные файлы:
7. Sashares 34 16.12.20 18:31 Сейчас в теме
(5) Не только кодировка отличается.
Вот этого нет в рабочем скрине:
"Content-Type: application/pdf; charset=utf-8"

Попробуйте другой кодировкой записать, windows-1251, например, или ANSI.

П.С. Стоит сравнивать запросы с закладки RAW - в ней будут видны как заголовки, так и тело.
9. gnp90 16.12.20 19:48 Сейчас в теме
(7)Ещё одно отличие нашел благодаря фидлеру, правильный запрос идет как form-data, а неправильный идет из XML
Скрин
Прикрепленные файлы:
11. Sashares 34 16.12.20 20:59 Сейчас в теме
(9) Обычно, при наличии правильного и HTTP запроса в фидлере не составляет сложности привести к нужному виду НTTP запрос в 1С. Сравнить заголовки, сравнить тело, что отличается - исправить.
По поводу кодировки при передаче файла - с таким не сталкивался, может там просто файлы разные?

Приложите RAW правильного запроса и файл для отправки для примера.
Завтра будет время, могу посмотреть.
15. uno-c 235 16.12.20 21:52 Сейчас в теме
(9) Это фидлер не понимает что Вы шлете. В неверном запросе лишний "Content-Type: application/pdf; charset=utf-8", которого вообще нет в рабочем скрине. И из-за неверного РазделительСтрок = Символ(10)+Символ(13); (нужен наоборот 13+10) у фидлера видимо крыша едет.
8. Sashares 34 16.12.20 18:44 Сейчас в теме
(5)Еще можно попробовать, без записи в поток.


...
ИмяФайла1 = ПолучитьИмяВременногоФайла("txt");

ЗаписьТекста = Новый ЗаписьТекста(ИмяФайла1);
ЗаписьТекста.ЗаписатьСтроку("--"+boundary);
ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьТекста.ЗаписатьСтроку("");
ЗаписьТекста.Закрыть();

ИмяФайла2 = ПолучитьИмяВременногоФайла("txt");

ИмяФайлаСДанными = ПолучитьИмяВременногоФайла("PDF");
ДД.Записать(ИмяФайлаСДанными );

ЗаписьТекста = Новый ЗаписьТекст(ИмяФайла2);
ЗаписьТекста.ЗаписатьСтроку("");
ЗаписьТекста.ЗаписатьСтроку("--"+boundary+"--");
ЗаписьТекста.Закрыть();

ИмяФайлаОтправки = ПолучитьИмяВременногоФайла("out");

МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ИмяФайла1);
МассивФайлов.Добавить(ИмяФайлаСДанными);
МассивФайлов.Добавить(ИмяФайла2);

ОбъединитьФайлы(МассивФайлов, ИмяФайлаОтправки);

ЗапросWeb.УстановитьИмяФайлаТела(ИмяФайлаОтправки);
...
Показать
13. uno-c 235 16.12.20 21:42 Сейчас в теме
(8) На АПИ телеграма такое не проходило из-за того, что Новый ЗаписьТекста(ИмяФайла1); устананавливал BOM - ненужные байты в начале. Их нужно либо потом убирать, либо как вариант Новый ЗаписьТекста(имяФайлаСПараметрами, "CESU-8"); - суррогат УТФ8 без БОМ.
14. Sashares 34 16.12.20 21:49 Сейчас в теме
(13)Удалить BOM не сложно.
После закрытия записи текста:
ДДанные = Новый ДвоичныеДанные(ИмяФайла1);    
    Если Сред(ДДанные, 1, 8) = "EF BB BF" Тогда
     Строка64 = Base64Строка(ДДанные);
     Строка64 = Прав(Строка64,СтрДлина(Строка64)-4); // Удаляем 3 символа BOM, для кодировки UTF-8
     ДДанные = Base64Значение(Строка64);
    КонецЕсли;
16. uno-c 235 16.12.20 21:54 Сейчас в теме
(14) Проще сразу их не писать. Новый ЗаписьТекста(имяФайлаСПараметрами, "CESU-8");
17. uno-c 235 16.12.20 21:59 Сейчас в теме
18. uno-c 235 16.12.20 22:09 Сейчас в теме
(14)
CESU-8 A Unicode code point from the Basic Multilingual Plane (BMP), i.e. a code point in the range U+0000 to U+FFFF, is encoded in the same way as in UTF-8

А эска дальше FFFF вообще не работает, поэтому в контексте 1С можно сказать, что UTF-8 и CESU-8 - это одинаковые кодировки.
Сообщить(КодСимвола(Символ(65534)));
Сообщить(КодСимвола(Символ(65535)));//FFFF
Сообщить(КодСимвола(Символ(65536)));
Сообщить(КодСимвола(Символ(65537)));
Сообщить(КодСимвола(Символ(65538)));

Сообщения:
65 534
65 535
-1
-1
-1
22. gnp90 17.12.20 08:12 Сейчас в теме
(2)
(14)Аааа так вот что это было, я как то пытался файл прочитать ADODB.Stream и получал именно "EF BB BF", подумал сначала хмм.. что то короткий файл, а оказывается это ВОМ
23. gnp90 17.12.20 08:34 Сейчас в теме
(11)Решение было на столько близко, что даже в глаза не попадало, РазделительСтрок был не по правилам собран, мне подсказал https://infostart.ru/profile/769742/, исправил его и все пошло, уж не знаю с чем ещё дальше столкнусь, но все ответы на мой вопрос дали ответы на многие тонкости, спасибо большое за активность. Если честно первый раз в жизни на форумах задаю вопросы, только отвечал, никогда не верил в этой, но благодаря всем вам у меня поменялось мнение кардинально....
Дальше буду мучать ЧестныйЗнак и Диадок, там уже подписи, шифрования всякие)Но там вроде половина уже сделана, т.е. авторизации, получения документов и т.д., теперь на очереди Отправка и тот же Мультипарт, но думаю (надеюсь), что теперь пойдут дела в гору))
На просторах интернета мало описания, как получится, постараюсь выложить примеры, для таких как я на будущее)) попытаюсь изложить все замечания и предложения что были предложены мне тут...
Ещё раз огромное спасибо....
24. Sashares 34 17.12.20 09:14 Сейчас в теме
20. uno-c 235 16.12.20 23:44 Сейчас в теме
(1)Вообще странное решение с этим РазделителемСтрок, и сам он неверный (нужно наоборот Символ(13)+Символ(10)) и можно вообще без него обойтись - эска сама по умолчанию все нормально перенесет.

Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", "");

Данные = ПолучитьСтрокуИзДвоичныхДанных(дд);

ЗапросWeb = Новый HTTPЗапрос("/decodefile/");
ЗапросWeb.Заголовки.Вставить("Content-Type","multipart/form-data; boundary=" + Boundary + "; charset=utf-8");

ТелоЗапроса = ЗапросWeb.ПолучитьТелоКакПоток();
ЗаписьДанных = Новый ЗаписьДанных(ТелоЗапроса, КодировкаТекста.UTF8, ПорядокБайтов.LittleEndian, , , Ложь);
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьДанных.ЗаписатьСтроку("");//перед данными дополнительный CRLF

ЗаписьДанных.Записать(дд);

ЗаписьДанных.ЗаписатьСтроку("");//бандери с новой строки
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--");
ЗаписьДанных.Закрыть();
Показать
2. platonov.e 158 16.12.20 16:33 Сейчас в теме
как на счет
ЗапросWeb.УстановитьТелоИзДвоичныхДанных(дд)


А еще ресурс какой то странный. Он ведет ведь в каталог
4. gnp90 16.12.20 16:43 Сейчас в теме
(2)Так пробовали, не помогло
6. uno-c 235 16.12.20 18:03 Сейчас в теме
Возьмите готовую процедуру из библиотеки Коннектор https://infostart.ru/public/709325/ Если стартманей нет - ищите его на гитхабе.
10. gnp90 16.12.20 19:55 Сейчас в теме
(8)
(5)Еще можно попробовать, без записи в поток.


...
ИмяФайла1 = ПолучитьИмяВременногоФайла("txt");

ЗаписьТекста = Новый ЗаписьТекста(ИмяФайла1);
ЗаписьТекста.ЗаписатьСтроку("--"+boundary);
ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьТекста.ЗаписатьСтроку("");
ЗаписьТекста.Закрыть();

ИмяФайла2 = ПолучитьИмяВременногоФайла("txt");

ИмяФайлаСДанными = ПолучитьИмяВременногоФайла("PDF");
ДД.Записать(ИмяФайлаСДанными );

ЗаписьТекста = Новый ЗаписьТекст(ИмяФайла2);
ЗаписьТекста.ЗаписатьСтроку("");
ЗаписьТекста.ЗаписатьСтроку("--"+boundary+"--");
ЗаписьТекста.Закрыть();

ИмяФайлаОтправки = ПолучитьИмяВременногоФайла("out");

МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ИмяФайла1);
МассивФайлов.Добавить(ИмяФайлаСДанными);
МассивФайлов.Добавить(ИмяФайла2);

ОбъединитьФайлы(МассивФайлов, ИмяФайлаОтправки);

ЗапросWeb.УстановитьИмяФайлаТела(ИмяФайлаОтправки);
...
Показать

(8)
(8)С этого мы начинали:) Не робит, у нас 3 API, Диадок, Честный знак и этот местный сервак) никуда не получилось) уже месяц бадаемся, силы на исходе
12. uno-c 235 16.12.20 21:12 Сейчас в теме
(10) Ну если так уж хочется без готовой библиотеки - то что я заметил:
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + РазделительСтрок);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8");


должно быть
ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" +ИмяФайлаДляЗагрузки+"""");
ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8"  + РазделительСтрок);


Сам РазделительСтрок не тот 10+13. RFC2045 -
The term CRLF, in this set of documents, refers to the sequence of octets corresponding to the two US-ASCII characters CR (decimal value 13) and LF (decimal value 10)
Т.е. должен быть 13+10.
Вообще когда я файлами мультипарт собирал - получалось, что ему достаточно ПС (10) - хоть и отклоняется от RFC - но проходило.
Ибо я использовал обычную ЗаписьТекста, которая по умолчанию в конце строки ставит только ПС.
ЗаписьТекста = Новый ЗаписьТекста(имяФайлаСПараметрами, "CESU-8"); //utf-8 без bom
// параметр "photo"
ИмяФайла = Строка(Новый УникальныйИдентификатор()) + "." + РасширениеФайлаКартинки;	
ЗаписьТекста.ЗаписатьСтроку("--"+boundary);
ЗаписьТекста.ЗаписатьСтроку("Content-Disposition: form-data; name=""photo""; filename=""" + ИмяФайла + """");
ЗаписьТекста.ЗаписатьСтроку("Content-Type: image/"+РасширениеФайлаКартинки);
ЗаписьТекста.ЗаписатьСтроку("");
// дальше присоединялись двоичные данные картинки
Показать
19. uno-c 235 16.12.20 23:04 Сейчас в теме
(12) Хотя нет, сейчас посмотрел - по умолчанию ЗаписьТекста.ЗаписатьСтроку везде в конце строки пишет байты 0D0A , т.е. символ.ВК+символ.ПС, они же Символ(13) + Символ(10). Это как раз то, что требует RFC2045 при формировании мультипарта.
21. gnp90 17.12.20 08:09 Сейчас в теме
(12)
РазделительСтрок

Блииин дружище..... Спасибо огроооомное!!!!! Я получил 200, чуть со стула не упал, радости полные штаны!!!!)))) Разделить не правильный был, как ты и сказал)) стоило только поменять местами 10 и 13 и все пошло) а ещё убрал явное представление формата файла "ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf; charset=utf-8" + РазделительСтрок);" заменил на "", судя по всему все формируется автоматически.....
Примного благодарен.. Честно...
Это был самый простой, местный, но думаю с остальными уже по накатанной пойдет, там ЧестныйЗнак и Диадок, думаю в общаг потом выложу куда нить, а то весь интернет облазил, как будто затирают все это....
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот