Имя: Пароль:
1C
1С v8
multipart/form-data files
,
0 SRM1C
 
22.12.20
08:26
Функция СоздатьСообщение()
        ВыборкаКартинок = Справочники.НоменклатураПрисоединенныеФайлы.Выбрать();
    // Формируем основное составное сообщение
    Разделитель = Строка(новый УникальныйИдентификатор());
    Результат = Новый Структура();
    Заголовки = Новый Соответствие();
    Результат.Вставить("Заголовки", Заголовки);
    Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + разделитель);
    Заголовки.Вставить("Authorization", "Basic b25lYzpzb21ldGhpbmdjcmVlcHk=");
    
    Тело = Новый ПотокВПамяти();
    
    ЗаписьДанных = Новый ЗаписьДанных(Тело);
    ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
    
    Текст = СоздатьСообщение_Текст("productId",Строка(СсылкаНаНоменлкатуру.УникальныйИдентификатор()));
    
    ЗаписьДанных.Записать(текст);
    ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель);
    Пока ВыборкаКартинок.Следующий() Цикл    
        //////////////
         //Создаем вложенные сообщения
         //Каждое вложенное сообщение представлено экземпляром типа
         //  ДвоичныеДанные
         //Это удобно, т.к. в данном случае внутренняя структура этих  
         // сообщений нам не интересна  
            Транспорт = СоздатьСообщение_Изображение("image",ВыборкаКартинок.Наименование+"."+ВыборкаКартинок.Расширение, ВыборкаКартинок.Ссылка);        
            ЗаписьДанных.Записать(Транспорт);
            ЗаписьДанных.ЗаписатьСтроку("--" + Разделитель + "--");
        /////////////////
    КонецЦикла;
    ЗаписьДанных.Закрыть();
    ДанныеТела = Тело.ЗакрытьИПолучитьДвоичныеДанные();
    Результат.Вставить("Тело", ДанныеТела);
    //Возврат Результат;
    
    
    Адрес = ПолучитьАдресСайта();
    Ресурс = "/v1/product-images";    
    
    НТТР = Новый HTTPСоединение(Адрес, , , , , , Новый ЗащищенноеСоединениеOpenSSL(неопределено, неопределено));
    
    НТТРЗапрос = Новый  HTTPЗапрос(Ресурс,Результат.Заголовки);
    НТТРЗапрос.УстановитьТелоИзДвоичныхДанных(Результат.Тело);
        
    
    Рез =  НТТР.ОтправитьДляОбработки(НТТРЗапрос);
    Если Число(Лев(Рез.КодСостояния,1)) >= 4 Тогда
        Ошибка = Рез.ПолучитьТелоКакСтроку();
        
    КонецЕсли;
КонецФункции

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

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


Если отправляю без картинок, только ИД номенклатуры, все норм, с картинками, ошибка "unexpected end of multipart data".

Код взят с сайта ИТС, который в котором пришлось заменить "==" на "--", иначе сервак не принимал запрос.
Добавив картинки, стала ошибка. Выборку картинок показал как пример, нужна помощь с самой ошибкой, получение данных из 1С нормально взято, из примерно удалил часть этого кода специально.
1 polosov
 
22.12.20
09:17
В очередной раз советую использовать модуль https://github.com/vbondarevsky/1connector
Там отправка файлов в одну строку.
2 polosov
 
22.12.20
09:24
Вот правильная ссылка https://github.com/vbondarevsky/Connector
3 Asmody
 
22.12.20
09:46
(2) Класс! просто и понятно. не то, что в БСП
4 Serginio1
 
22.12.20
09:58
(3) Ну да, на .Net еще понятнее
http://catalog.mista.ru/1c/articles/466052/
5 Asmody
 
22.12.20
10:22
(4) .Net внутри 1С выглядит как инородное тело.

вот это вообще ужас и кошмар

врап=новый COMОбъект("NetObjectToIDispatch45");
    HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
    HttpClientHandler = врап.ПолучитьТип("System.Net.Http.HttpClientHandler");

    // Контенты для Post
    
    MultipartFormDataContent=Врап.ПолучитьТип("System.Net.Http.MultipartFormDataContent");
    StreamContent  =Врап.ПолучитьТип("System.Net.Http.StreamContent");
    StringContent  =Врап.ПолучитьТип("System.Net.Http.StringContent");
    ByteArrayContent=Врап.ПолучитьТип("System.Net.Http.ByteArrayContent");
    FormUrlEncodedContent =Врап.ПолучитьТип("System.Net.Http.FormUrlEncodedContent");

     DecompressionMethods= Врап.ПолучитьТип("System.Net.DecompressionMethods");

    ServicePointManager=врап.ПолучитьТип("System.Net.ServicePointManager");
    Dictionary=Врап.ПолучитьТип("System.Collections.Generic.Dictionary`2[System.String,System.String]");
    StringBuilder=Врап.ПолучитьТип("System.Text.StringBuilder");
    String=Врап.ПолучитьТип("System.String");    
    HttpUtility=Врап.ПолучитьТипИзСборки("System.Web.HttpUtility","System.Web.dll");
6 polosov
 
22.12.20
10:45
(4) Тебе бы сделать нормальную обертку, по типу (2). Чтобы инкапсулировать все лишнее.
7 Serginio1
 
22.12.20
10:48
(5) Угу как там типы в 1С в 30 и более символов?
Зато все понятно, и таких типов в 1С нет. Да и вынес получение типов как using в отдельный метод, а дальше пиши как и в 1С.
Это просто расширение языка без всяких ВК.
И куча примеров в том же stackoverflow
(6) Так чем это хуже 2

Процедура Multi_PartНажатие(Элемент)
    // Вставить содержимое обработчика.
    uriSources =ПолучитьСтрокуЗапроса("http://localhost.fiddler:40320";);
    //uriSources ="http://localhost:40320";;
    HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll");
    MultipartFormDataContent=Врап.ПолучитьТип("System.Net.Http.MultipartFormDataContent");

    
    Клиент = Врап.СоздатьОбъект(HttpClient);
    Контент = Врап.СоздатьОбъект(MultipartFormDataContent);
    Клиент.BaseAddress =Врап.СоздатьОбъект("System.Uri",uriSources);
    
    
    // Вариант отправки Ключ-Значение
    Значения = Врап.СоздатьОбъект("System.Collections.Generic.Dictionary`2[System.String,System.String]");

     Значения.Add("Name", "name");
     Значения.Add("id", "id");
  

                //      content.Add(new FormUrlEncodedContent(values));
                Для каждого КлючЗначение из Значения Цикл

                    Контент.Add(Врап.СоздатьОбъект("System.Net.Http.StringContent",КлючЗначение.Value),КлючЗначение.Key);
                КонецЦикла;
                
                
                // Вариант отправки двоичных данных из массива
                Encoding=Врап.ПолучитьТип("System.Text.Encoding");
                
                СтроковыйКонтент =Врап.СоздатьОбъект("System.Net.Http.ByteArrayContent",Encoding.UTF8.GetBytes("Тестовая строка"));

                ContentDisposition=Врап.СоздатьОбъект("System.Net.Http.Headers.ContentDispositionHeaderValue","form-data");
                ContentDisposition.FileName ="ПростоСтрока";
                ContentDisposition.Name ="attachment";


                СтроковыйКонтент.Headers.ContentDisposition = ContentDisposition;
                СтроковыйКонтент.Headers.ContentType = Врап.СоздатьОбъект("System.Net.Http.Headers.MediaTypeHeaderValue","text/plain");
                Контент.Add(СтроковыйКонтент);

                
                // Вариант отправки двоичных данных из файла
                ИмяФайла ="C:/ТестXML";
            
                ПотокФайла =Врап.ПолучитьТип("System.IO.File").OpenRead(ИмяФайла);
                ФайловыйКонтент =Врап.СоздатьОбъект("System.Net.Http.StreamContent",ПотокФайла);
                ContentDisposition=Врап.СоздатьОбъект("System.Net.Http.Headers.ContentDispositionHeaderValue","form-data");
                ContentDisposition.FileName = Врап.ПолучитьТип("System.IO.Path").GetFileName(ИмяФайла);
                
                ФайловыйКонтент.Headers.ContentDisposition = ContentDisposition;
                ФайловыйКонтент.Headers.ContentType = Врап.СоздатьОбъект("System.Net.Http.Headers.MediaTypeHeaderValue","application/octet-stream");
                Контент.Add(ФайловыйКонтент);

                 // Вариант отправки двоичных данных из файла но более краткий
                 ПотокФайла2 =Врап.ПолучитьТип("System.IO.File").OpenRead(ИмяФайла);
                 ФайловыйКонтент2 =Врап.СоздатьОбъект("System.Net.Http.StreamContent",ПотокФайла2);
                 Контент.Add(ФайловыйКонтент2,"attachment","TestXml");

                requestUri = "api/values/SendFiles";

                Результат = Клиент.PostAsync(requestUri, Контент).Result;
                стр = Результат.Content.ReadAsStringAsync().Result;
                
                Сообщить(стр);
                ЗакрытьРесурс(Клиент);
                ЗакрытьРесурс(Контент);
                ЗакрытьРесурс(ПотокФайла);

// Вот как выглядит отправляемый запрос                
//POST http://localhost:40320/api/values/SendFiles HTTP/1.1
//Content-Type: multipart/form-data; boundary="9f2d525a-7383-46ab-8fc7-419d73486c02"
//Host: localhost:40320
//Content-Length: 811
//Expect: 100-continue
//Connection: Keep-Alive

//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Type: text/plain; charset=utf-8
//Content-Disposition: form-data; name=Name

//name
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Type: text/plain; charset=utf-8
//Content-Disposition: form-data; name=id

//id
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; filename="=?utf-8?B?0J/RgNC+0YHRgtC+0KHRgtGA0L7QutCw?="; name=attachment
//Content-Type: text/plain

//Тестовая строка
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; filename="=?utf-8?B?0KLQtdGB0YJYTUw=?="
//Content-Type: application/octet-stream

//12345
//--9f2d525a-7383-46ab-8fc7-419d73486c02
//Content-Disposition: form-data; name=attachment; filename=TestXml; filename*=utf-8''TestXml

//12345
//--9f2d525a-7383-46ab-8fc7-419d73486c02--

КонецПроцедуры
8 polosov
 
22.12.20
10:49
(7) Ты смеешься?
Посмотри как файлы отсылаются в (2).
9 Asmody
 
22.12.20
10:51
(8) Ему просто очень нравится нажимать на кнопки. Ну или платят за количество строчек
10 Serginio1
 
22.12.20
10:59
(8) Там в примере несколько вариантов отправки файлов, потоков, сток, пар ключей
И завернуть все в 1 метод не проблема.

              // Вариант отправки двоичных данных из файла но более краткий

    Процедура ОтправитьФайл(Контент, ИмяФайла)
                 ПотокФайла2 =Врап.ПолучитьТип("System.IO.File").OpenRead(ИмяФайла);

                 ФайловыйКонтент2 =Врап.СоздатьОбъект("System.Net.Http.StreamContent",ПотокФайла2);

                 Контент.Add(ФайловыйКонтент2,"attachment","TestXml");
КонецПроцедуры
11 Asmody
 
22.12.20
11:05
(10) В 95% случаев не нужно "несколько вариантов бла-бла-бла". И эта задача должна решаться функцией в 1 строку.
Весь бойлерплейт должен быть внутри библиотеки
12 Serginio1
 
22.12.20
11:06
Я к тому, что на каждый чих писать ВК или Ком компоненту замучаешься.
Можно, для сокращения написать на C# класс с более простым интерфейсом и использовать её без регистрации через NetObjectToIDispatch45 только и всего
13 polosov
 
22.12.20
11:19
(12) В данном случае все тоже самое делается на 1С. Зачем использовать тогда обертку над C#?
В (2) все реализовано на 1С.
14 oleg_km
 
22.12.20
11:19
(11) Ну я делаю библиотеку как обработку на 1С. В нее инкапсулирую часть связанного с .NET кода. А так действительно это столько уже бы пришлось написать компонент на шарпе, да еще их распространять на компы нужно. А так одна точка входа в дотнет.
15 Serginio1
 
22.12.20
11:22
(13) Не все. На самом деле вариантов отправки там вагон и маленькая тележка.
Ну и не на всех версиях есть поддержка multipart/form-data

Кстати как там в 1С с DecompressionMethods.GZip,DecompressionMethods.Deflate
Раньше не было
16 polosov
 
22.12.20
11:32
(15) а ты загляни в модуль из (2). Очень красиво реализовано.
17 Serginio1
 
22.12.20
11:45
(16) Искать лень. Кинь код. На .Net это
handler = врап.СоздатьОбъект(HttpClientHandler);
handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ;
  
Клиент=Врап.СоздатьОбъект(HttpClient,handler);
18 polosov
 
22.12.20
11:49
(17) А там все автоматом делается, если в заголовке присутствует указание на сжатие.
19 Serginio1
 
22.12.20
11:51
(18) То есть в 1С добавили DecompressionMethods.GZip,DecompressionMethods.Deflate?
20 Serginio1
 
22.12.20
11:54
Во всяком случае из недавнего приседают со сторонней библиотекой
чтение - декодирование ответа  HTTP POST запроса
21 polosov
 
22.12.20
11:58
(19) Нет, не добавили. просто человек разобрался как можно сделать типовыми средствами.
22 Serginio1
 
22.12.20
12:02
(21) Ну ты код то покажи или ссылку
23 polosov
 
22.12.20
12:10
(22)
Функция ПрочитатьGZip(СжатыеДанные) Экспорт
    
    РазмерПрефиксаGZip = 10;
    РазмерПостфиксаGZip = 8;
    
    ЧтениеДанных = Новый ЧтениеДанных(СжатыеДанные);
    ЧтениеДанных.Пропустить(РазмерПрефиксаGZip);
    РазмерСжатыхДанных = ЧтениеДанных.ИсходныйПоток().Размер() - РазмерПрефиксаGZip - РазмерПостфиксаGZip;
    
    ПотокZip = Новый ПотокВПамяти(ZipРазмерLFH() + РазмерСжатыхДанных + ZipРазмерDD() + ZipРазмерCDH() + ZipРазмерEOCD());
    ЗаписьДанных = Новый ЗаписьДанных(ПотокZip);
    ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipLFH());
    ЧтениеДанных.КопироватьВ(ЗаписьДанных, РазмерСжатыхДанных);
    
    ЗаписьДанных.Закрыть();
    ЗаписьДанных = Новый ЗаписьДанных(ПотокZip);
    
    CRC32 = ЧтениеДанных.ПрочитатьЦелое32();
    РазмерНесжатыхДанных = ЧтениеДанных.ПрочитатьЦелое32();
    ЧтениеДанных.Закрыть();
    
    ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipDD(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных));
    ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipCDH(CRC32, РазмерСжатыхДанных, РазмерНесжатыхДанных));
    ЗаписьДанных.ЗаписатьБуферДвоичныхДанных(ZipEOCD(РазмерСжатыхДанных));
    ЗаписьДанных.Закрыть();
        
    Возврат ПрочитатьZip(ПотокZip);
    
КонецФункции
24 Serginio1
 
22.12.20
12:13
(23) Ок. Спасибо. Тут понятно он добавляет данные для чтения Zip.
А для Deflate.
25 polosov
 
22.12.20
12:14
(24) Для Deflate нет пока. Сделай и оформи PR. Думаю по аналогии можно.
26 polosov
 
22.12.20
12:19
(24) Хотя 1С поддерживает Deflate. Возможно и код из (23) справится.
27 Serginio1
 
22.12.20
12:29
(26) Ну судя по http://catalog.mista.ru/public/618906/ еще нет.
Ну врукопашную то конечно можно все на 1С переписать и потратить кучу времени или взять уже готовые и приспособить под себя затрачивая минимум времени.
Например та же задача для парсинга сайта.
http://catalog.mista.ru/public/466196/
28 polosov
 
22.12.20
12:31
(27) Но ты же понимаешь, что надо хотя бы базово знать C#
29 oleg_km
 
22.12.20
12:34
(28) Ну не вижу в этом проблемы для программиста. Я наоборот после того как 1С подвело меня сначала с ИнтернетПочта, потом с ИнтернетСоединение, вообще перевожу на дотнет все, что доступно на дотнет. У дотнет сколько бета-тестеров, а у 1С?
30 polosov
 
22.12.20
12:41
(29) Да конечно не проблема. Можно и картриджи заправлять и чайники чинить.
31 polosov
 
22.12.20
12:52
(29) Вот уйдешь ты от своего работодателя, придет другой прог, а ему надо будет поправить чего-нибудь. А у него в резюме не было "Знание 1С+С#"
32 Serginio1
 
22.12.20
12:57
(30) А алгоритм Deflate писать на 1С!
Суть использования внешних библиотек это сократить время на программирования и создание эффективного кода.
Не хочешь использовать твой выбор. Например если я умею программировать на C# многое в 1С мне значительно проще делать, чем брать чью то непроверенную библиотеку.
В том же stackoverflow полно примеров для решения кучи задач.
(31) Ну ничего, там разобраться то неделю. И поверь программистов C# в мире значительно больше. Всегда можно найти для решения неких задач.
Просто знать 1 язык, это как то не по программистски. А если знаешь несколько языков то понять C# несложно. Вон Гений1С сразу проникся и начал писать на C#
33 polosov
 
22.12.20
13:01
(32) Да в курсе я этого. Я, например, на в с++ могу. Но при поиске прога 1С гораздо сложнее найти человека со знанием нескольких языков.
34 Serginio1
 
22.12.20
13:11
(33) Ну обычно все работают не с отдельными одноэсниками а с франчайзи и прочими. А там обычно есть разные программисты.
В любом случае изучить то .Net не проблема. Что это за программист который не может изучить другой язык? Там глубоких знаний не нужно. Только типы, методы свойства.
35 polosov
 
22.12.20
13:14
(34) Проблемы нет, для некоторых.
Но ты к примеру сравни оформление кода и документацию в (2) и описание в своих статьях. компетентным везде быть невозможно.
36 Serginio1
 
22.12.20
13:26
(35) Ну я в статьях продвигаю использование .Net.
В реалиях проще написать dll с классом с нужными методами как в (2)
При этом сами классы и типы параметров в методах могут быть не COM совместимы.
В большинстве случаев берем примеры со stackOverflow. И кладем эту библиотеку рядом с NetObjetToIDispatch45.dll
или в макет и распаковываем в нужное место.