1с что можно передать с клиента на сервер
Обмен большими данными между клиентом и сервером
Проблематика.
Пути решения проблемы.
Как это устроено. Общее описание ландшафта.
Для простоты считаем, что существует сервер предприятия на хосте srv1c, на котором размещена информационная база base1. В базе внедрена библиотека ПередачаДанных. Информационная база и http-сервисы на веб-сервере Apache2.4, опубликованном на хосте srvweb со следующими endpoint-ами:
Адреса методов «ПередачаДанных»
Endpoint | Наименование | Метод | Описание | Роли | Способ публикации |
---|---|---|---|---|---|
/base1 | сама база | Позволяет открыть базу в вебклиенте, в тонком клиенте по WS-ссылке | Зависит от конфигурации | ||
/base1/hs/dt/storage/ХранилищеИИдентификатор | Операции с файлами в логическом хранилище по идентификатору. | | |||
get | Запрос получает токен на скачивание файла из логического хранилища | Полные права, удаленный доступ | Публикация без явного указания учетных данных. Требует аутентификации | ||
post | Запрос получает токен на загрузку файла в логическое хранилище | Полные права, удаленный доступ | Публикация без явного указания учетных данных. Требует аутентификации | ||
/base1/hs/dt/volume/ | ТомИПутьКФайлу | ||||
get | Запрос получает токен на скачивание файла из тома | Полные права, удаленный доступ | Публикация без явного указания учетных данных. Требует аутентификации | ||
post | Запрос получает токен на загрузка файла в том | Полные права, удаленный доступ | Публикация без явного указания учетных данных. Требует аутентификации | ||
/base1/hs/dt/download/ | Получить | get | По предварительно полученному токену отдает клиенту данные | Полные права, передача данных (анонимный доступ) | Публикация под учетной записью служебного пользователя, которому назначена только роль «Передача данных (анонимный доступ)» |
/base1/hs/dt/upload/ | Отправить | put | По предварительно полученному токену загружает данные от клиента на сервер | Полные права, передача данных (анонимный доступ) | Публикация под учетной записью служебного пользователя, которому назначена только роль «Передача данных (анонимный доступ)» |
1. Формируем запрос. Он может быть сформирован как через вызовы методов http-сервиса ХранилищеИИдентификатор и ТомИПутьКФайлу (в этом случае необходимо указать свои учетные данные для аутентификации), так и с помощью серверного вызова: «РегистрСведений.ВременныеИдентификаторыЗапросов.ЗарегистрироватьЗапрос». В этом случае дополнительная аутентификация не нужна, использутся учетные данные текущего сеанса.
2. Ответ на запрос содержит токен. В дальнейшем этот токен используется для анонимного доступа к сервисам «передачи данных». Токен может быть использован только для той операции, которая была запрошена в запросе. Нельзя запросить скачивание файла А, а вместо этого загрузить на сервер файл Б. Токен действителен в течение 10 минут после регистрации запроса. После каждого обращения по токену время его жизни продляется на 10 минут.
3. Запрос может отправлять и получать как данные целиком, так и какую-то порцию. Это поведение регулируется http заголовком Content-Range.
Пример реализации загрузки данных на сервер в тонком клиенте
Рассмотрим последовательность действий, которые необходимо совершить для отправки данных из тонкого клиента на сервер. Предполагаем, что http-сервис настроен и опубликован. Считаем, что файл доступен через диалог выбора файла и выбираем его:
далее следует неудобная для листинга цепочка якобы асинхронных вызовов, получение размера файла итд. Этот этап пропустим, переходим сразу к загрузке.
Вызов «ЗаполнениеПараметровПубликацииНаСервере» регистрирует запрос на сервере от имени текущего пользователя, что в дальнейшем позволит анонимно отправлять http запросы без аутентификации. Образец работы с библиотечными вызовами будет приложен в файлах. Далее инициализируются http соединение, запрос уже на анонимный http сервис upload. Открывается файловый поток на чтение и последовательно вычитывается в буфер указанное в настройках количество байт. Запрос дополняется заголовком «Content-Range», используемым на сервере для «склейки» фрагментов передаваемого файла, и отправляется на сервер. Эта процедура циклически повторяется, пока все данные из файла не будут переданы. Последний ответ сервера содержит идентификатор файла в логическом хранилище (для его дальнейшего использования).
Пример реализации скачивания данных с сервера в тонком клиенте
На самом деле немного сложнее, но об этом в последнем разделе
Пример реализации загрузки данных на сервер в веб-клиенте
В веб клиенте всё сильно сложнее. На момент разработки веб клиент позволял либо выбрать файл и поместить его сразу во временное хранилище (метод «НачатьПомещениеФайла» до платформы версии 8.3.13 не позволял отказаться от помещения файла в ВХ), либо требовал установки расширения для работы с файлами, чтобы показать диалог выбора файла. А после ещё и дополнительно запрашивал разрешения на чтение файла ещё раз. И это даже не самое страшное. Веб клиент не позволяет создавать http запросы в коде.
А вот java script позволяет. Поэтому было принято решение для веб клиента экспроприировать диалог выбора файла прямо из браузера со всеми стилями и использовать его в своих корыстных целях. HTML форма диалога выбора файла позволяет перетаскивать файл(ы) drag’drop-ом, сразу несколько (хотя это и запрещено в примере), показывает полосу прогресса (чего в 8.3.15 так и не сделали), ну и конечно же работает с библиотекой «Передача данных». Более подробно смотрите внешнюю обработку в приложениях к статье.
Концепт скачивания данных с сервера в веб-клиенте
Можно это делать тем же способом, как предложено в п.5. Однако тут начинаются неприятные неожиданности на этапе открытия ссылки для скачивания. Браузер непонятно чем занимается, крутит колесико минуту-несколько, потом, возможно показывает диалог скачивания файла, а нередко ошибку 504. Что бы это значило, задумался я?
На просторах интернета было найдено решение по рекомендации «лучших собаководов». Оно достаточно зависит от используемого веб-сервера.
Методика называется «контролируемая загрузка», состоит в следующем. Клиент запрашивает какой то ресурс. В нашем случае: https://host/ib/hs/dt/download/queryid. Вебсервер передает этот запрос на backend (на сервер предприятия), который добавляет в ответ специальные заголовки, которые говорят вебсерверу, какой файл отдавать. Примеры (правда для php) можно посмотреть в этой статье на хабре. Здесь приведу пример для nginx в режиме reverse proxy.
1. В конфиге нашего сервера объявляем дополнительный «internal» location. Это важно. Доступ к файловой системе, указанной в этом location будет только у сервера, клиенты даже случайно не смогут получить доступа к содержимому каталога или даже самим файлам по прямой ссылке. Возможно использование как локальных файловых систем, так и смонтированных cifs и nfs шар.
2. В коде http-сервиса на стороне сервера предприятия добавляем специальные заголовки к ответу. В отличие от стандартной передачи файла в ответе сервера, в тело ответа не добавляются двоичные данные файла, а используется заголовок «X-Accel-Redirect«. В переменной ИмяФайла формируется путь до файла в location, например, если файл фактически находится в /some/path/protected/file1.txt, то в переменной ИмяФайла должно находиться значение /protected/file1.txt. Ознакомиться с документацией по этому механизму можно здесь
PPS: файл внешней обработки «выдирался» из конфигурации, возможно содержит ошибки. Тестирование проводилось на конфигурации Менеджер сервиса 1.0.83.10. Если будут проблемы, с удовольствием помогу разобраться в комментариях и/или обновлениях статьи.
Передача файла с клиента на сервер
В общем случае клиент и сервер 1С — это разные компьютеры с различной файловой системой. Рассмотрим как правильно передать файл с компьютера клиента на компьютер сервера.
Метод асинхронной передачи файла на сервер
Обмен файлом между клиентом и сервером осуществляется через временное хранилище. Для помещения данных во временное хранилище правильно воспользоваться методом
НачатьПомещениеФайла ( ОписаниеОповещенияОЗавершении >, Адрес >, ПомещаемыйФайл >, Интерактивно >, УникальныйИдентификаторФормы >, ОписаниеОповещенияПередНачаломПомещенияФайла >)
Метод работает в асинхронном режиме. Возможны два варианта выбора файла для передачи на сервер:
Параметр ОписаниеОповещенияОЗавершении содержит описание процедуры (тип ОписаниеОповещения), которая будет вызвана после завершения помещения файла во временное хранилище. Эта процедура должна иметь ключевое слово Экспорт и 4 параметра:
Следует обратить внимание на параметр УникальныйИдентификаторФормы. В него рекомендуется передавать идентификатор текущей формы для сохранения данных во временном хранилище между несколькими серверными вызовами. При закрытии формы данные из временного хранилища будут автоматически удалены.
Неинтерактивная передача файла на сервер
Рассмотрим пример неинтерактивной передачи файла на сервер, без вызова окна выбора файла:
&НаКлиенте
Процедура ЗагрузитьФайл ( Команда )
&НаСервере
Процедура ВыполнитьЗагрузкуНаСервере ( Адрес )
// Получение данных из временного хранилища
Данные = ПолучитьИзВременногоХранилища ( Адрес );
// Получение имени временного файла
ИмяВременногоФайла = ПолучитьИмяВременногоФайла ( «xml» );
// Сохранение данных во временный файл
Данные.Записать ( ИмяВременногоФайла );
// Хорошим тоном будет удалить временный файл
Попытка
При интерактивном выборе файла дополнительно необходимо предусмотреть два момента:
Интерактивная передача файла на сервер
Рассмотрим, пример интерактивной передачи файла на сервер:
&НаКлиенте
Процедура ЗагрузитьФайлИнтерактивно ( Команда )
&НаКлиенте
Процедура ЗагрузитьФайлЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры ) Экспорт
// Файл выбран
ВыполнитьЗагрузкуНаСервере ( Адрес );
// Пользователь отказался от выбора файла
Сообщить ( «Файл не был выбран» );
Процедура ВыполнитьЗагрузкуНаСервере при интерактивном и неинтерактивном режимах одинаковая.
Передача файла на сервер средствами БСП
В конфигурациях со встроенной Библиотекой стандартных подсистем для передачи файлов с клиента на сервер можно использовать процедуры
общего модуля ФайловаяСистемаКлиент или
общего модуля ОбменДаннымиКлиент.
Пример интерактивной загрузки файла на сервер средствами БСП:
&НаКлиенте
Процедура ЗагрузитьФайлИнтерактивно ( Команда )
Если ПустаяСтрока ( ТекстОшибки ) И ПустаяСтрока ( Адрес ) Тогда
ТекстОшибки = НСтр ( «ru = ‘Ошибка передачи файла на сервер’» );
Если НЕ ПустаяСтрока ( ТекстОшибки ) Тогда
Остались вопросы?
Спросите в комментариях к статье.
Как в 1С передать таблицу значений с клиента на сервер
Как корректно передавать данные между клиентом и сервером в управляемых формах, например таблицы значений или выборки?
Проще всего сделать передачу поместив таблицу значение во временно хранилище.
Вроде должно работать 🙂
Еще можно преобразовать таблицу в какой нибудь другой типа данных.
Видел как то такое извращение:
Передаем переменную в любую процедуру — хоть клиентскую, хоть серверную.
И там делаем вот такое:
Подпишитесь на наш YouTube канал
Таблицу значений &НаКлиенте не создать и, соответственно, в хранилище не сложить, в тонком и web клиентах ТЗ недоступна
ЗначениеИзСтрокиВнутр на Тонком клиенте не проканает:
ЗначениеИзСтрокиВнутр (ValueFromStringInternal)
Синтаксис:
Тип: Строка.
Системное представление значения в строковом виде.
Возвращаемое значение:
Тип: Произвольный.
Значение, полученное из строкового системного представления.
Описание:
Преобразует значение из строкового системного представления во внутреннее.
Сервер, толстый клиент, внешнее соединение. Для тонкого клиента недоступно :о(
Связаться с нами можно по телефону:
Наша команда предоставляет услуги по консультированию, настройке и внедрению 1С.
Услуги и цены можно увидеть по ссылке.
Будем рады помочь Вам!
Свежие записи
Подписывайтесь на наш YouTube канал, чтобы узнать больше о 1С. Там вы найдете множество видео-уроков. Ждем вас!
При использовании данного сайта, вы подтверждаете свое согласие на использование файлов cookie в соответствии с настоящим уведомлением в отношении данного типа файлов. Если вы не согласны с тем, чтобы мы использовали данный тип файлов, то вы должны соответствующим образом установить настройки вашего браузера или не использовать сайт
Заметки из Зазеркалья
Данная статья является анонсом новой функциональности.
Не рекомендуется использовать содержание данной статьи для освоения новой функциональности.
Полное описание новой функциональности будет приведено в документации к соответствующей версии.
Полный список изменений в новой версии приводится в файле v8Update.htm.
Реализовано в версии 8.3.11.2867.
Во время длительной серверной операции пользователь всегда хочет видеть на клиенте ход её выполнения. Для того чтобы оценить, сколько времени осталось до её завершения, или насколько быстро она выполняется. Чтобы это реализовать, необходимо каким-то образом передавать информацию с сервера на клиента. Но и раньше, и сейчас взаимодействие между клиентской и серверной частью 1С:Предприятия происходит только по инициативе клиента. Сервер 1С:Предприятия сам, по своему желанию, не может вызвать какое-либо клиентское приложение и передать ему информацию.
Однако с появлением системы взаимодействия возник ещё один способ «общения» клиентских приложений и сервера между собой. В ней сообщения могут отправляться не только интерактивно, но и программно, причём по инициативе любого из участников. Мы доработали систему взаимодействия и реализовали возможность передачи информации с сервера в клиентское приложение на её основе.
Основные возможности и сценарии
Передача информации происходит по инициативе сервера. Поскольку в качестве транспорта используется система взаимодействия, то способы адресации определяются её возможностями. Вы можете адресовать информацию либо всем клиентским приложениям, либо только тем приложениям, которые запущены перечисленными пользователями. Клиентское приложение может подписаться на сообщения сервера и программно обрабатывать их по мере появления.
В клиентское приложение вы можете передавать данные, имеющие XDTO-сериализацию. Естественно типы передаваемых данных должны быть доступны на клиенте. Вы можете использовать передачу информации с сервера в клиентское приложение в самых разных сценариях. Например:
Пример использования
Проще всего объяснить новый механизм на конкретном примере, когда длительная операция, выполняемая на сервере, состоит из нескольких этапов. По мере выполнения очередного этапа вы хотите извещать клиентское приложение об этом. Чтобы клиентское приложение некоторым образом показывало пользователю ход выполнения этой операции.
Общая схема очень простая. Вы создаёте отдельное обсуждение, в котором передаёте сообщения клиенту. Назовём такое обсуждение служебным. Клиентское приложение автоматически обрабатывает новые сообщения в этом обсуждении и выполняет нужные действия.
Дальше начинаются нюансы. Если ваша задача предполагает, что все клиентские приложения должны каким-то образом автоматически реагировать на информацию, поступающую с сервера, тогда вы можете создать единственное служебное сообщение, и добавить в состав его участников специальный идентификатор, обозначающий всех пользователей. Такой идентификатор можно получить с помощью нового типа СтандартныеПользователиСистемыВзаимодействия.ВсеПользователиПриложения. В таком обсуждении сообщения будут доставляться всем пользователям системы, и тем, которые есть сейчас, и тем, которые появятся в будущем.
Но если ваша задача состоит в том, чтобы информацию с сервера передавать именно тому приложению, которое инициировало длительную серверную операцию, то в этом случае лучше создать несколько служебных обсуждений, для каждого пользователя своё.
Разница заключается в следующем. Сервер взаимодействия удерживает соединение с каждым клиентским приложением. Когда вы отправляете сообщение в обсуждении, в котором участвуют все пользователи, сервер взаимодействия задействует все соединения с клиентскими приложениями.
Если же в обсуждении участвует один пользователь, то будет задействовано одно соединение с его клиентским приложением.
Правды ради нужно сказать, что от имени одного пользователя может быть запущено несколько приложений. Но сути дела это не меняет. Если информацию с сервера нужно передать в то приложение, которое инициировало серверную операцию, эффективнее использовать отдельные служебные обсуждения для каждого пользователя, чем «пулять» по всем клиентам в одном общем служебном обсуждении. В этом случае ресурсы сервера взаимодействия будут использоваться бережнее, а нагрузка на него будет меньше.
Итак, для каждого пользователя нужно создать своё служебное обсуждение. Это можно представить следующей схемой:
Приятным моментом является то, что сделать это нужно всего лишь один раз. Удобнее всего это делать в том месте прикладного решения, в котором создаются новые пользователи. Для идентификации обсуждения можно использовать новое свойство Ключ.
Процедура СоздатьСлужебноеОбсуждение(КлючСлужебногоОбсуждения) Экспорт Если СистемаВзаимодействия.ПолучитьОбсуждение(КлючСлужебногоОбсуждения) = Неопределено Тогда Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение(); Обсуждение.Отображаемое = Ложь; Обсуждение.Ключ = КлючСлужебногоОбсуждения; Обсуждение.Участники.Добавить(СистемаВзаимодействия.ИдентификаторТекущегоПользователя()); Обсуждение.Записать(); КонецЕсли; КонецПроцедуры Функция КлючСлужебногоОбсуждения() Экспорт Возврат «Сообщения сервера » + СистемаВзаимодействия.ИдентификаторТекущегоПользователя(); КонецФункции |
Ключ может быть любым, но важно, чтобы он был уникальным в пределах информационной базы, и каким-то образом связан с конкретным пользователем. Например, в ключе можно использовать идентификатор пользователя. На сервере этот ключ поможет определить, в какое обсуждение отправлять сообщения, а на клиенте этот ключ поможет понять, на какое обсуждение нужно подписаться.
Ещё одно новое свойство обсуждения будет вам полезно – Отображаемое. Для служебных обсуждений его лучше устанавливать в Ложь, тогда они не будут показаны в пользовательском интерфейсе.
Итак, создание служебного обсуждения это действие, которое нужно сделать один раз, при создании нового пользователя. А вот что нужно делать при каждом запуске клиентского приложения, так это подписываться на служебное обсуждение, предназначенное текущему пользователю. Для этого менеджеру системы взаимодействия мы добавили новый метод НачатьПодключениеОбработчикаНовыхСообщений():
Метод асинхронный, поэтому его запись выглядит немного громоздко. Но ничего сложного в нём нет. Всё, что он делает, это подключает вашу процедуру (ОбработкаСообщенийСервера) в качестве обработчика новых сообщений обсуждения, на которое указывает ключ, передаваемый во втором параметре.
Теперь вы можете на сервере отправить сообщение в служебное обсуждение, и приложение, подписанное на это обсуждение, автоматически его обработает.
В настоящее время в Библиотеке стандартных подсистем (БСП) реализован механизм выполнения длительных операций на сервере, который использует фоновые задания. Это позволяет распараллелить исполнение прикладного кода на сервере и освободить пользовательский сеанс.
В этом примере необходимо использовать ту же самую механику.
Длительную операцию, которая должна исполняться на сервере, нужно запустить как фоновое задание. Каждое фоновое задание исполняется в отдельном системном сеансе. В результате после того, как вы запустите фоновое задание, исполнение кода в пользовательском сеансе вернётся на клиента, и клиент будет готов к дальнейшим действиям. Например, к тому, чтобы обрабатывать сообщения, появляющиеся в служебном обсуждении.
Тут желательно учесть ещё один момент. От имени одного и того же пользователя может быть одновременно запущено несколько клиентских приложений. Все они подписаны на служебное обсуждение этого пользователя. Значит, все они отреагируют на сообщение, которое появится в этом обсуждении. А это нехорошо.
Поэтому при запуске фонового задания желательно снабдить его уникальным идентификатором, который передать в само фоновое задание, и кроме этого вернуть на клиента. Тогда клиент будет знать «свои» фоновые задания, а фоновое задание, посылая сообщение, сможет однозначно себя идентифицировать.
Запуск фонового задания может выглядеть таким образом:
Идентификатор фонового задания, возвращённый на клиента, вы можете сохранить в глобальном массиве, чтобы он был доступен процедуре, обрабатывающей новые сообщения.
А длительная операция, выполняемая на сервере, может выглядеть так:
Здесь на каждом этапе длительного алгоритма посылается сообщение в служебное обсуждение, а в конце посылается сообщение, сигнализирующее о завершении задания. В данных сообщения передаётся идентификатор этого задания, какое-либо значение, которое нужно обработать на клиенте, и способ его обработки. Способ обработки может понадобиться потому, что этот механизм вы можете использовать в разных алгоритмах своего прикладного решения. В одном алгоритме, например, нужно передвинуть полосу индикатора, а в другом – вывести надпись в форму.
И, наконец, на клиенте процедура, обрабатывающая новые сообщения, может выглядеть так:
&НаКлиенте Процедура ОбработкаСообщенийСервера(Сообщение, ДополнительныеПараметры) Экспорт // Наше ли фоновое задание. ИндексЗадания = ИдентификаторыЗаданий.Найти(Сообщение.Данные.ИдентификаторЗадания); Если НЕ ИндексЗадания = Неопределено Тогда // Как обрабатывать это сообщение. Если Сообщение.Данные.СпособОбработки = «Индикатор» Тогда Состояние(«Выполняется обработка данных», Сообщение.Данные.Значение); ИначеЕсли Сообщение.Данные.СпособОбработки = «НеОтслеживать» Тогда ИдентификаторыЗаданий.Удалить(ИндексЗадания); КонецЕсли; КонецЕсли; КонецПроцедуры |
Сначала вы определяете, «ваше» ли это фоновое задание (его идентификатор сохранён в глобальном массиве), затем смотрите, как нужно обработать переданное значение. В одном случае, для примера, вы передвигаете индикатор, а в другом удаляете идентификатор из массива отслеживаемых заданий, потому что задание завершилось.
Заключение
Как вы видите механизм довольно гибкий. И это позволяет использовать его для самых разных задач. Приведённый пример это лишь один из сценариев, как говорится, «в лоб».
Существуют и другие, более изощрённые сценарии. Например, когда длительная операция (загрузка данных) инициируется одним из пользователей, а известить о ходе её выполнения нужно группу пользователей, которые с этими данными работают.
Другая область задач связана с тем, что информация не просто доставляется в клиентское приложение, а сервер некоторым образом «отдаёт команды» приложениям, заставляя их выполнить те или иные действия. Например, обновить итоговые данные, отображаемые в отдельном окне, или схему выполнения некоторого глобального прикладного процесса. Или корректно завершить работу клиентского приложения, если администратору системы нужно перезагрузить сервер, а пользователя нет на рабочем месте.
Поэтому после выпуска этого функционала мы с интересом познакомимся с примерами его реального использования и будем готовы рассматривать и обсуждать ваши пожелания и замечания к этому механизму.