1с объединить файлы multipart form data
(обязательный). Тип - Строка. Адрес ресурса на сервере.
(обязательный). Тип - Строка. Имя файла на диске, в который
помещаются данные, полученные от сервера (ответ сервера).
(необязательный). Тип - Строка. Заголовки, добавляемые к запросу на сервер.
Текстовые пары вида :, разделенные комбинацией ВК + ПС.
(подробнее о заголовках будет сказано ниже).
Рассмотрим параметры процедуры Получить() более подробно:
В поле ИмяВыходногоФайла указывает имя файла на диске, в который будут сохранены данные, полученные от сервере в результате запроса. Так, например, если сервер возвращает список пользователей в формате XML, то на диск в указанный файл будет сохранен XML файл со списком пользователей.
О заголовках более подробно будет сказано ниже.
Так же, при запросе к веб-серверу зачастую передаются дополнительные данные (параметры) для этого запроса. Параметры от адреса источника отделяются символом "?". Каждый параметр задается в формате =. Параметры от адреса источника отделяются символом "?". Сами же параметры отделяются друг от друга символом "&". В результате строка адреса источника может выглядеть следующим образом: getUsers.php?owner_id=263544&count=100.
Ниже приведен пример, поясняющий все выше сказанное.
Код 1C v 8.х
Все заголовки разделяются на четыре основных группы:
От себя лишь добавлю, что, если это явно не указано в требованиях к отправке данных веб-серверу заголовки HTTP для метода GET можно не указывать. Для метода POST обычно нужно указать заголовки Content-Type (тип передаваемых данных, например: "Content-Type: text/html;charset=utf-8") и Content-Length (размер передаваемых данных в байтах, например: "Content-Length: 1348").
Напомню, что HTTP заголовки в 1С указываются строкой в виде текстовых пар ":", разделенных комбинацией символов ВК+ПС.
Также заголовки можно задать типом Соответствие, где в качестве ключа указывается заголовок, а в качестве значения - значение заголовка.
Ниже приведены поясняющие примеры:
Код 1C v 8.х
Поле АдресРесурса аналогично полю Источник процедуры Получить(), т.е. указывается строка с адресом запроса, идущая после имени домена и символа "/".
Поле ИмяВыходногоФайла также аналогично одноименному полю процедуры Получить(), т.е. содержит имя файла, в котором будут сохранены данные, полученные от сервера в результате обработки исходных данных.
О заголовках было упомянуто выше. Напомню лишь, что для метода POST обычно указываются заголовки Content-Type и Content-Length. В качестве параметра заголовка Content-Length указывается размер файла-источника, преобразованный с помощью функции XMLСтрока().
Ниже приведен пример, поясняющий все выше сказанное.
Код 1C v 8.х
где:
- id пользователя на сайте, от имени которого добавляется комментарий;
- id материала на сайте, к которому добавляется комментарий;
- текст комментария.
Предположим, что нам уже известны id пользователя и материала и они хранятся в переменных user_id и post_id. Ниже приведен пример, решающий нашу задачу.
Код 1C v 8.х
Загрузка файлов (изображений, документов и т.п.) на веб-сервер методом POST.
Зачастую возникает необходимость загрузки файлов на веб-сервер. Это может быть, например, изображение к статье на сайте, или фотография для альбома, или архив для файлообменника. Ранее мы рассматривали передачу методом POST параметров или просто файлов. Таким же образом можно и передавать двоичные файлы. Но как быть, если файлы необходимо отправлять вместе с параметрами? Для возможности отправки файлов в этом случае используется HTTP заголовок ContentType:multipart/form-data. Следует заметить, что обычно таким способом передаются файлы через веб-браузеры. Т.е. когда на сайте вы выбираете файл и нажимаете кнопку "Загрузить", то файл передается способом описанным ниже. При таком способе сам файл также задается как переменная, т.е., например, файл передается через параметр file или image. Однако, мы не можем просто передать file=. А вот как все таки передать файл мы и рассмотрим ниже.
Bounday можно сформировать, например, таким образом
Код 1C v 8.х
Все данные отделяются друг от друга разделителем boundary. Начинать разделитель нужно с "--":
Код
В конце данных нужно закрыть разделитель, добавили в конце разделителя "--", т.е. вид будет "----".
Итак, например, нам нужно передать на веб-сервер текстовый файл через параметр "text", его описание через параметр "desc" и id пользователя через параметр "uid", для которого будет загружен наш файл.
Предположим, что файл содержит следующий текст:
Мороз и солнце; день чудесный!
Еще ты дремлешь, друг прелестный -
Пора, красавица, проснись:
Открой сомкнуты негой взоры
Навстречу северной Авроры,
Звездою севера явись!
Описание должно содержать "Стих А.С. Пушкина", а id пользователя равно "0123456". Тогда файл должен быть сформирован следующим образом (для упрощения предположим, что bounday мы уже сформировали и он равен "ccf8111910")
Код
--ccf8111910
Content-Disposition: form-data; name="uid"
0123456
--ccf8111910
Content-Disposition: form-data; name="desc"
Стих А.С. Пушкина
--ccf8111910
Content-Disposition: form-data; name="text"; filename="stih.txt"
Content-Type: text/plain
Мороз и солнце; день чудесный!
Еще ты дремлешь, друг прелестный -
Пора, красавица, проснись:
Открой сомкнуты негой взоры
Навстречу северной Авроры,
Звездою севера явись!
--ccf8111910--
А теперь перейдем непосредственно к 1С. Пусть у нас будет форма с реквизитами "Пользователь", "Описание" и "ИмяФайла". Реализуем отправку данных, описанным выше способом
Код 1C v 8.х
Передача текстовых файлов таким способом проблем не вызывает. Сложнее дело обстоит с файлами, содержащими двоичные данные (изображения, архивы и т.п.). Все дело в том, что в 1С просто нет методов для чтение двоичных файлов в строку. Если мы делаем обмен со своим сайтом, которые сами и разрабатывали, то можно просто преобразовать файл в строку Base64 при помощи процедуры Base64Строка(), а на стороне сервера преобразовать строку Base64 обратно.
Код 1C v 8.х
А как же быть если мы загружаем файл на сторонний сервер, который принимает файл как есть без преобразование его в строку Base64(). В это случае можно пойти на хитрость. В 1С есть процедура ОбъединитьФайлы(), которая объединяет несколько файлов на диске в один результирующий файл
Код 1C v 8.х
(обязательный). Тип - Массив. Массив имен частей файлов, которые
требуется объединить. Объединение будет происходить в порядке, в котором заданы
имена файлов в массиве.
(обязательный). Тип - Строка. Имя файла, который будет
создан в результате объединения файлов.
Т.е. мы можем сформировать текстовый файл с запросом, объединить его с файлом(-ами), которые необходимо передать на веб-сервер и передать уже файл, получившийся в результате объединения исходных файлов. Ниже демонстрируется процесс передачи двух zip архивов на сервер с дополнительными параметрами user_id и post_id.
Код 1C v 8.х
Ну вот, вроде бы, и все, что я хотел рассказать о способах передачи файлов и данных на веб-сервер из 1С. Если что-то не понятно, что-то хотите уточнить или нашли ошибки - пишите в комментариях.
Автор: Павел
Местный босс - администратор
В статье собран мой опыт по передаче данных на веб-сервер.
В ходе реализации одного проекта потребовалось организовать автоматическую передачу данных на веб-сервер посредством регламентного задания.
Покопавшись прежде всего в мануалах, синтаксис-помощнике 1С Предприятия, порыскав в Сети, с удивлением обнаружил наличие отсутствия каких-либо вменяемых материалов по теме. Вернее, материалы в Сети есть, но там больше вопросы с абстрактными ответами.
Все нижеприведённые примеры кода всего лишь примеры, хоть и взяты из рабочей конфигурации.
Прежде всего необходимо создать файл отправки данных (собственно содержимое POST-запроса) и, при необходимости, подготовить двоичные данные.
Определяем разделитель разделов — границу boundary в POST-запросе в формате RFC (подробнее MIME: Организация данных ). В качестве границы может быть использована строка, состоящая из латинских букв и цифр.
Чтобы ничего не выдумывать, воспользуемся штатным классом 1С Предприятия УникальныйИдентификатор .
Содержимое файла ответа будет представлять собой какой-либо контент, отданный скриптом на стороне веб-сервера агенту пользователя. Подробнее смотрите пример скрипта php и скриншот ниже.
Подготавливаем двоичные данные. В моём случае это файл архива zip, но может быть что угодно, хоть изображение.
Передача содержимого файла
В 1С Предприятии отсутствуют средства чтения двоичных файлов в обычную строку, как в PHP или PERL.
Одним из способов получения строкового содержимого двоичного файла является кодирование с помощью штатных функций Base64Строка() или XMLСтрока(), при этом размер передаваемых данных увеличивается примерно на 30%. Декодировать содержимое файла на сервере можно при помощи функции php base64_decode() или аналогичных для используемого вами серверного ПО.
Другой способ состоит в использовании штатной функции ОбъединитьФайлы(, ) (подробнее см. в СП). В этом случае формирование файла POST-запроса будет происходить немного сложнее.
Оба способа описаны ниже.
Впрочем, двоичные данные лучше закодировать, иначе при приёме на веб-сервере файл может быть повреждён или не принят вовсе, если он будет содержать URL-значащие символы. Особенно это касается XML-подобных или иных текстовых файлов.
Следует также помнить об ограничениях хостинга и контролировать размер передаваемых данных. Как правило, для php это 2Мб. (см. файл /usr/local/php5/php.ini)
; Maximum allowed size for uploaded files.
upload_max_filesize = 2M
В противном случе, на веб-сервере вы получите пустой POST-запрос.
В жизни любого программиста попадаются задачки, которые человека цепляют. Вот не нравится стандартный метод решения и все! А порой бывает, что стандартные решения не подходят по какой-то причине. Некоторые люди обходят такие задачи стороной, другие же любят решать их. Можно даже сказать сами их находят. Одна из таких задач отсылка файла или несколько файлов методом POST.
Как же нам тогда решить эту задачку? Для этого надо взглянуть как собственно передаются данные методом POST. Единственный вариант решения — это передача файла составным запросом с помощью multipart/form-data. Этот метод хорошо описан в RFC7578. Давайте взглянем как будет выглядеть тело POST запроса multipart/form-data:
Осталось, собственно, написать программу реализующий этот метод. Так как мы люди умные и не пишем по сто раз одно и тоже в разных проектах, то оформим все в виде класса реализующий этот метод. Плюс к этому, расширим его для разных вариантов отправки как файлов, так и простых элементов формы. А что бы отличить среди массива POST данных, наличие файла, создадим отдельный файл — контейнер с содержимым файла и его данных (имя и расширение). Таким образом он будет выглядеть следующим образом:
Теперь собственно сам класс по формированию тела multipart/form-data для POST запроса:
Данный класс состоит из нескольких методов. Метод — PartPost формирует отдельные части составного запроса, а метод — Get объединяет эти части и формирует тело POST запроса в формате — multipart/form-data.
Теперь у нас есть универсальный класс для отправки тела POST запроса. Осталось написать программу использующую данный класс для отправки файлов на удаленный Web сервер. Воспользуемся библиотекой CURL:
Если CURL не подходит, то данную библиотеку можно применить и для отправки через сокеты. Ну и собственно ссылки на источники:
Задача: отправка и обработка файлов с помощью FormData и FileReader в форме со всеми возможными полями и пересылкой дополнительных параметров для каждого поля c объединением всех данных формы (кроме файлов и системных полей) в общий массив.
Поддержка: все современные браузеры, IE 10+.
Плагины: jquery-2.1.4
Для начала разберемся, что же такое FormData
Formdata — тип данных в рамках технологии XHR2, данные в нем хранятся в виде пар ключ / значение.
new Formdata () — это конструктор для создания объекта FormData.
FormData имеет множество методов для полноценной работы с ней, таких как:
- .get() — возвращает данные по ключу;
- .getAll() — возвращает массив всех значений, ассоциированных с этим ключом;
- .has() — возвращает булевое значение касательно наличия объекта;
- .set() — добавляет значение к уже существующему ключу и, если его нет, создает его;
- .append() — создает новую пару ключ / значение;
- .delete() — удаляет объект по ключу;
- .forEach() — на нем остановимся подробнее:
Главная проблема FormData заключается в Internet explorer (как всегда), а вернее, в его поддержке. Из всех методов, которые есть в FormData, Internet explorer поддерживает только append(), что уничтожает всю простоту использования. Следовательно, мы не можем собрать форму с помощью простого вызова конструктора и последующего изменения данных в ней, и придется это делать вручную:
- Получим все данные формы через serializeArray(), переберем, проверим их на пустоту и, вместе с заголовком (data-title), если это не системное поле (type=”hidden”), занесем в ассоциативный массив, отдельный для каждого поля, а далее добавим в наш массив для данных формы.
- Системные поля мы сразу добавляем методом append() в FormData.
Теперь познакомимся с FileReader
FileReader — это объект, который позволяет веб-приложениям асинхронно читать содержимое файлов (или буферы данных), хранящиеся на компьютере пользователя, используя объекты File или Blob, с помощью которых задается файл или данные для чтения.
С его помощью мы будем отслеживать загрузку файлов на клиенте, формировать список загруженных файлов и выводить для них прогресс бар.
Теперь к самой задаче
Форма, которую мы будет пересылать:
Для удобства пользователей предоставим им возможность добавления сразу большого количества файлов. С этой целью укажем в поле name значение file[] и атрибут multiple, с ограничением только картинки accept=«image».
Для пользователей также будем выводить список файлов, которые они загрузили с раздельным progress bar-ом для каждого файла и возможностью удаления перед отправкой. И тут мы столкнулись с проблемой. Дело в том, что fileList (массив загруженных файлов) у нашего input предназначен только для чтения, и удалить только выбранный пользователем файл мы не можем. Так что было решено перед отправкой на сервер сверять список, который уже сформировал пользователь, с тем что уже загружено. И при совпадении со списком файл будет добавляться в FormData.
1) Создаем саму функцию отправки через ajax:
2) Создаем функцию сборки формы:
3) Оборачиваем все это в функцию для удобного вызова по событию:
4) Вешаем функцию на событие клика на кнопку отправки формы:
Теперь у нас есть полноценный отправщик формы, осталось только написать обработчик для файлов.
1) Создадим функцию отслеживания состояния input type=file:
2) Напишем обработчик ошибок:
3) Напишем функцию для переборки файлов в fileList нашего input type=file:
4) Теперь непосредственно сам обработчик:
5) Добавим возможность удаления файлов из списка:
6) Можем использовать наш отправщик, не забыв поднять локальный сервер:
Это продолжение статей
Например, нет асинхронных запросов, сжатия трафика, отправки составного содержимого и т.д.
Для начала объявим используемые типы при открытии.
По мере использования я буду пояснять, для чего тот или иной тип.
Вызываем задачу так
Для теста множества асинхронных запросов сделал функцию
Имитируем задержку в 1 секунду. Например, нам нужно выполнить 100 запросов.
Если бы при синхронном выполнении нам понадобилось бы минимум 100 сек, то при асинхронном уходит порядка 1,5 сек.
Отдельно нужно отметить использование ServicePointManager. Более подробно можно посмотреть здесь
Есть еще вариант дождаться всех запросов
Перед тем как перейти к использованию multipart/form-data, покажу примеры отправки Post запросов.
Отправляемый контекст можно задавать пятью способами
- MultipartFormDataContent,
- StreamContent,
- StringContent,
- ByteArrayContent,
- FormUrlEncodedContent
Выбирайте тот, который удобен. FormUrlEncodedContent это аналог отправики данных Form при Post Submit.
Теперь перейдем к отправке multipart/form-data.
Сжимает трафик в 5 раз.
Related Posts
22 Comments
(0) Я не нашел, какие требования к Framework?
(0) Перед публикацией могли хотя бы отформатировать код (Alt+Shift+F)
Форматировал. Только вот вставка в редактор и редактирование на этом сайте не совсем тривиальная задача
Спасибо за труды, о великий!
Спасибо за оценку трудов моих скромных.
Вкратце можно описать интерфейс
Это работает только на клиенте, так как идет привязка к событиям, а на сервере нужно ждать когда событие придет
Вся беда в том, что на сервере нельзя сделать
ДобавитьОбработчик Выполнитель.ПриОкончанииВыполненияЗадачи, ПриОкончанииВыполнения
Поэтому асинхронные только на клиенте.
Извините, возможно плохо искал. А как получить изображение через Стр=Клиент.GetStringAsync(«GetHeaders»).Result; как двоичные данные?
Или есть другой метод получения?
Ну или хотябы как записывать
Спасибо, методом проб и ошибок нашел одно из решений которое в вдругой ветке предоставили
Если есть Другие более «правильные» варианты подскажите пожалуйста. Вообще не дотнет разработчик
Ну в Данные ты получаешь массив байтов.
Сергей, спасибо за ответ. Только я имел ввиду Как из запроса получить двоичные данные как объект 1С , вот нашел такое решение. Можно конечно попробовать и по другому
Т.е. я не могу обработать task через wait() или waitall(). Не знаю как правильно решить данный момент. Пока сделал что жду в цикле возвращение True хотя бы одного из свойств;
Хотя это немного наверное не правильно…
(1) Ты можешь смотреть IsFaulted в ПриОкончанииВыполнения к которой подключаешься
Нет, я тут не пользуюсь Асинхронным выполнителем, посмотрел что для моей задачи это немного «Неудобно». я просто создаю массив заданий. Причем массив как объект 1С. И когда нужно прохожусь по этому массиву.
Все равно процедура ПриОкончанииВыполнения начнет выполнятся только после завершения формирующей процедуры. Насколько я правильно понимаю
ПриОкончанииВыполнения будет вызываться после завершения Задачи.
Немного проверил работу асинхронного выполнителя. Немного не вижу в нем смысла.
Дело в том, что если мы в Процедуре А() создаем выполнителю множество задач, то результат задач в процедуре-Обработчике мы сможем получить Только. После выполнения всей процедуры А. Кроме случаев Когда 1С сама не вызывает «асинхорнные» процедуры , например Вопрос().
Единственное что дает Выполнитель — это гарантированное выполнение задачи (task), но существенно ухудшает читаемость кода.
Но на выполнение можно сделать проверку в коде 1С циклом как я писал выше
Тема очень хороша, спасибо.
Ну а ты создавай в Процедуре А только задачи, на это уходит миллисекунды.
А вот время для получения результата уже могут быть секунды.
Нет в данном случае возвращается Task и у него можно проверить IsFaulted
Извиняюсь за вопрос, но на Win 10 x64 получаю стабильно ошибку «Неверное имя объекта» на первой строке Врап = Новый COMОбъект
Читайте также: