Некоторые особенности реализации веб-сервисов. Решение проблемы длительных операций и интерактивного отображения статуса выполняемой операции в PHP К сложным, с точки зрения XML сериализации, относятся типы

Алексей Багрянцев Октябрь 3, 2012

В процессе работы мы не раз сталкивались с проблемой выбора решения для той или иной задачи. Порой можно, не особо мучаясь, взяться за самый очевидный и распространенный метод как говориться, “решать в лоб”. В большинстве случаев такой подход так или иначе даст результат, но он может затребовать от вас серьезных умственных и временных затрат.

Поэтому в ситуации, когда перед вами стоит нестандартная задача, возможно, стоит отойти от привычных методов, а попробовать рассмотреть несколько вариантов, пусть даже они поначалу кажутся не слишком удачными или к ним просто неохота прибегать, потому что “обычно мы так не делаем”. Тут главное не бояться экспериментировать, потестировать каждый из методов, и наконец, выбрать наиболее подходящий, отвечающий всем вашим запросам и обеспечивающий требуемый результат.

Нам, разработчикам, с такими проблемами приходиться бороться очень часто. Об одной такой сложной и трудоемкой задаче, потребовавшей перебора нескольких подходов к ее решению, и пойдет речь ниже.

Предыстория

На одном из PHP проектов среднего размера возникли проблемы, связанные с выполнением тяжеловесных операций и интерактивном отображении статуса исполняемой операции. Кроме блокировки исполнения других запросов и перехода по другим ссылкам портала пользователь пребывал в неведении и не догадывался, что же происходит в данный момент времени, когда же закончится операция, возможно, произошла ошибка и т.д. Проект изначально носил статус экспериментального, требования к выполняемым фазам часто менялись на лету, изменялись приоритеты и вектор развития системы. Для формирования большего представления хотелось бы описать стек используемых технологий на проекте:

  • MVC Framework CakePHP 2.1 (PHP5.3);
  • MySQL;
  • jQuery, jQuery UI, jQuery plugins;
  • Selenium server, Snoopy server side browser simulator;
  • IMAP Server, etc.

В качестве операционной системы была выбрана: CentOS

Выбор фреймворка был обусловлен опытом его использования командой разработчиков, выбор же реляционной СУБД MySQL в качестве data storage является довольно стандартным решением и обусловлено стабильностью и распространенностью использования этой СУБД в качестве “движка” хранения данных.

На этапе проектирования системы сразу было трудно предугадать, что в системе появятся очень “тяжелые” операции, процесс выполнения которых придется пересматривать, реализовывать дополнительные компоненты и в общем перерабатывать архитектуру приложения. К тому же система была неким прототипом, где требования часто менялись, как и то, куда будет расти система в дальнейшем.

На одном из этапов был реализован ряд операций, которые оказались довольно “тяжеловесными” (highweighted operations) и мало того, что они блокировали выполнение других операций в рамках той же сессии, но и вообще процесс перехода по ссылкам системы становился невозможным до тех пор, пока “тяжелая” операция не была завершена. При рассмотрении проблемы на более низком уровне оказалось, что любой запрос блокировал файл сессии при его открытии, соответственно, пока операция не выполниться полностью и процесс не сбросит (flush) сессионные данные в файл сессии и не освободит его, сняв блокировку, другие запросы будут терпеливо ждать в очереди. Действительно, по умолчанию в PHP в качестве механизма хранения сессий используется файл. При открытии сессии срабатывает функция, наподобие fopen(), которая и блокирует файл на чтение и запись для других процессов. Сразу напрашивается решение о смене session storage для снятия блокировки, но поговорим об этом попозже.

Подходы

  1. Разбиение операции на шаги
  2. Ajax Polling
  3. Long Polling
  4. Forever lframe
  5. Streaming
  6. Comet-server
  7. Web-sockets

Коротко рассмотрим каждый из этих подходов для решения задачи выполнения тяжеловесных операций и интерактивного оповещения пользователя о прогрессе выполнения .

Разбиение операции на шаги

Первое что приходит в голову - операцию разделить на шаги. После выполнения очередного шага и отправки ответа браузеру пользователя, он инициирует следующий шаг сам, отправив соответствующий ajax-запрос на сервер.

В выполняемом проекте данный подход оказался не слишком удачным по причине того, что тяжеловесные операции были практически не делимы на шаги. Кроме того использовались сторонние и запущенные на сервере сервисы, для работы с которыми приходилось создавать и подготавливать соответствующие объекты во время исполнения запроса. После исполнения запроса, которые представлял 1 шаг операции, объекты “прибивались”. Возможно стоило подумать о их переиспользовании, но до мы этого не дошли.

Ajax Polling

Следующее решение, которое напрашивается, заключается в запуске операции на сервере и постоянном опросе сервера о статусе выполняемой операции путем посылки серии ajax-запросов через определенные интервалы времени. На клиенте же можно проанализировать такой ответ сервера (например, это может быть JSON, содержащий “message”, “percentage”, “error” и “redirect”) и отрисовать progress-bar, отображающий статус выполнения текущей операции.

Была попытка использования Polling подхода на проекте с двумя разными способами хранения результата выполнения операции:

    Хранение результатов выполнения в файле – +.txt

    Хранение результатов в БД, в соответствующей таблице – high_weight_operations

Пользователь инициировал выполнение операции с помощью ajax-запроса, после этого клиентский скрипт периодически опрашивал сервер и получал статус и прогресс текущей операции – /operations/get_status/ .

Но мы столкнулись со следующей проблемой: длительная операция стартовала, но блокировала файл сессии, тем самым исключала возможность выполнения параллельных запросов в рамках той же сессии. Иными словами, после запуска длительной операции все запросы, опрашивающие сервер, попадали в очередь и ждали момента, когда основной запрос освободит файл сессии.

Первое решение возникшей проблемы заключалась в освобождении файла сессии. Для этого в PHP предусмотрена функция – session_write_close() , с помощью которой можно закрыть сессию на запись. Действительно, можно запустить операцию, прочесть данные сессии, сделать в них изменения и закрыть сессию на запись.

Но в реалиях проекта, с учетом устоявшейся архитектуры, данное решение применить не удалось. Требовалась запись сессии во многих местах длительной операции. К тому же такое решение нельзя назвать “чистым”, т.к. пользователю, возможно, понадобиться ”попутешествовать” по сайту или запустить еще одну тяжелую операцию параллельно. Поэтому нужна была альтернатива.

Решение заключалось в смене Session Storage, что обеспечивало работу с сессией без блокировки при ее открытии. В качестве нового хранилища сессии можно выбрать один из следующих вариантов:

  • MySQL Database;
  • MongoDB;
  • Memcached;

Для того, чтобы сменить Session Storage в PHP предусмотрена функция – session.save_handler() , которая устанавливает пользовательские функции хранения сессии. Они используются для хранения и получения данных, ассоциированных с сессией. В сети можно найти множество примеров её использования, существуют уже реализованные классы, служащие для переноса сессии в БД или memcached.

Примечание : Для работы функции необходимо установить опцию session.save_handler в значение user в вашем файле конфигурации php.ini .

На проекте в качестве эксперимента было использовано хранение сессий в mysql и mongodb.

Примечание : Если понадобится, чтобы только что записанный в сессию параметр был доступен для других запросов, то сессию необходимо “сбосить (flush)” в mysql или mongodb, чтобы отработала функция записи сессии. Для этого необходимо закрыть её на запись и переоткрыть снова:

Public function session_flush() { session_write_close(); session_start(); }

После реализации соответствующих компонент, сессия перестала блокироваться и позволила обрабатываться нескольким запросам, ассоциируемых с одной и той же сессией, одновременно. Теперь она не “лочится” (lock ), как это было с файлами, при открытии файла функцией fopen , плюс ко всему скорость работы сессии значительно возросла.

Примечание : Для использования mongodb в PHP необходимо установить mongodb как сервис, а также драйвер работы на PHP.

Пример установки на CentOS :

  1. Создать репозиторий

/etc/yum.repos.d/10gen.repo

  1. Заполнить содержимым (в зависимости от разрядности ОС)

name=10genRepository

baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64

  1. Вызвать
  1. Далее

yum install mongo-10gen mongo-10gen-server

  1. Запустить “демон”

service mongod start

  1. Установить драйвер

yum -y install php-devel

sudo pecl install mongo

extension=mongo.so

После этого можно спокойно пользоваться mongodb .

В качестве примера прилагаю листинг компоненты CakePHP для переноса Session Storage и MongoDB

Mongo = new Mongo($connection_string); /* indexes */ $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}->ensureIndex("id", array("id" => 1)); $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}->ensureIndex("id", array("id" => 1, "expires" => 1)); // Register this object as the session handler if ($this->forceSaveHandler) { session_set_save_handler(array($this, "open"), array($this, "close"), array($this, "read"), array($this, "write"), array($this, "destroy"), array($this, "gc")); } $this->_timeout = Configure::read("Session.timeout") * 60; } public function __destruct() { try { $this->mongo->close(); session_write_close(); } catch (Exception $e) { } } public function open() { return true; } public function close() { $probability = mt_rand(1, 150); if ($probability <= 3) { $this->gc(); } return true; } public function read($id) { $cursor = $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}->find(array("id" => $id)); if ($cursor->count() == 1) { $cursor->next(); } else { return false; } $result = $cursor->current(); if (!empty($result) && isset($result["data"])) { return $result["data"]; } } public function write($id, $data) { if (!$id) { return false; } $expires = time() + $this->_timeout; $session = array("id" => $id, "data" => $data, "expires" => $expires); $filter = array("id" => $id); $options = array("safe" => true, "fsync" => true,); $collection = $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}; if ($collection->findOne($filter) == null) { return $collection->insert(am(array("_id" => new MongoId($id)), $session), $options); } else { return $collection->update($filter, array("$set" => $session), am($options, array("upsert" => false))); } } public function destroy($id) { return $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}->remove(array("id" => $id), true); } public function gc($time = null) { if (empty($time)) { $time = time(); } return $this->mongo->{self::MONGO_DATABASE}->{self::MONGO_COLLECTION}->remove(array("expires" => array("$lt" => $time)), true); } }

Реализация компоненты для переноса сессий в MySQL аналогична и отличается лишь в реализации функций gc(), destroy(), open(), write(), read(), close()

Примечание : Не забудьте изменить конфигурационный файл core.php проекта.

Configure::write("Session", array("defaults" => "database", "handler" => array("engine" => "MongoSession")));

Также можно добавить защиту на количество одновременных запросов в рамках одной сессии. На нашем проекте этим занималась отдельная компонента, отвечающая за тяжеловесные операции в целом – HighWeightedOperationsComponent.php, которая отслеживала количество операций, запущенный в рамках одной сессии и в зависимости от настроек разрешала запускать строго определенное количество операций.

Итог:

    Сменен Session Storage. Блокировок сессии больше нет.

    На клиенте инициируется ajax-запрос на старт операции.

    Реализована серия Polling-запросов на обновление статуса и progress-bar.

    Создана компонента управления “тяжелыми операциями”.

Long polling

Подход схож с предыдущим, но есть существенное отличие: в первом случае клиент сам опрашивает сервер на наличие изменений, в этом же случае устанавливается непрерывное соединение с сервером и сервер сам сигнализирует о появлении изменения. Преимущество данного подходя заключается в уменьшении трафика между клиентом и сервером.

Принцип: клиентский скрипт обращается к серверу и говорит: "Eсли у тебя появятся данные, я их готов сразу забрать, а потом снова подключусь". В некоторых реализациях сервера существует буферизация, когда сервер не сразу отдает данные, а ждет: вдруг сейчас появится что-то еще, тогда отправлю все сразу. Но такая буферизация вредна, так как вносит задержки, а мы хотим достичь максимальной скорости! После получения данных браузер должен снова открыть новое соединение. Длительность такого соединения может измеряться часами, но это в теории. Обычно время намного меньше и максимум достигает 5 минут, после которых просто создается новое соединение. Делается это потому, что серверы не любят такие долгоживущие сессии, да и сам протокол HTTP не очень приспособлен к такому использованию.

На проекте такой подход использован не был, но обсуждения были.

Forever IFrame

Коротко: На странице создается скрытый iFrame, который инкрементально рендерит информацию о прогрессе операции или выполняет java-скрипты. Но для этого HTTP-сервер и PHP должны быть настроены так, чтобы умели отдавать данные кусочно в процессе выполнения операции. Об этом рассказано подробно в следующем пункте.

Итак, мы инициируем выполнение операции через скрытый на странице элемент iFrame. На сервере операция отдает данные вызов кусочно и тут-же отсылает клиенту ответ, IFrame пытается выполнить присланный ответ:

Streaming

Подход экспериментально был использован на проекте.

Возникла идея, а что если попробовать инициировать выполнение операции ajax-вызовом, на сервере кусочно отдавать (стримать) данные клиенты. Тогда, возможно, на клиенте каждый раз при получении очередной порции данных, будет срабатывать какое-то событие, по которому мы сможем обновить соответствующий блок и отобразить статус выполнения.

Сначала нам нужно было найти и применить соответствующие настройки для Apache-сервера и PHP, что привело к поиску информации в сети и серии тестов. В итоге настройки выглядят следующим образом:

Public function prepare() { // Turn off output buffering ini_set("output_buffering", "off"); // Turn off PHP output compression ini_set("zlib.output_compression", false); // Implicitly flush the buffer(s) ini_set("implicit_flush", true); ob_implicit_flush(true); // Clear, and turn off output buffering while (ob_get_level() > 0) { // Get the curent level $level = ob_get_level(); // End the buffering ob_end_clean(); // If the current level has not changed, abort if (ob_get_level() == $level) break; } // Disable apache output buffering/compression if (function_exists("apache_setenv")) { apache_setenv("no-gzip", "1"); apache_setenv("dont-vary", "1"); } }

Была написана компонента полностью реализующий данный подход. Но после более глубокого анализа оказалось, что данный подход не применим, т.к. на клиенте отсутствуют события, сигнализирующие о том, что очередная порция данных пришла от посланного ранее ajax-запроса. По событию onSuccess приходят данные полностью целиком.

Comet-сервер

Согласно “Wikipedia”, Comet - любая модель работы web-приложения, при которой постоянное HTTP-соединение позволяет веб-серверу отправлять данные браузеру без дополнительного запроса со стороны браузера.

Общая черта таких моделей состоит в том, что все они основаны на технологиях, непосредственно поддерживаемых браузером (например, JavaScript), а не на проприетарных плагинах.

На данном проекте была попытка использования реализации Comet-сервера Dklab Realplexor .

Dklab Realplexor - это Comet-сервер, позволяющий держать одновремено сотни тысяч долгоживущих открытых HTTP-соединений с браузерами пользователей. JavaScript-код, запущенный в браузере, подписывается на один или несколько каналов Realplexor-а и вешает обработчик на поступление данных. Сервер может в любой момент записать сообщение в один из таких каналов, и оно будет моментально передано всем подписчикам (хоть одному, хоть тысяче), в режиме реального времени и с минимальной нагрузкой для сервера.

Web-sockets

Также обсуждалась возможность использования WebSockets. Но от этого подхода мы отказались по причине “не поддержки” старых браузеров.

WebSocket - протокол полнодуплексной связи поверх TCP-соединения, предназначенный для обмена сообщениями между браузером и веб-сервером в режиме реального времени.

Итог:

В результате задача была реализована Polling-подходом, с переносом сессий в MongoDB. Но последующие обсуждения, увеличение количество “тяжеловесных” задач и их сложности привели к применению более стандартного и надежного решения – реализации очереди выполняемых задач с использованием CRON-планировщика. Действительно, после проверки всех прав на исполняемую операцию мы можем сохранить ее контекст в базу (таблица cron_taks), предварительно сериализовав его. На сервере по определенным интервалам времени будет запускаться CRON shell, который будет брать очередную задачу из очереди, менять ее статус на IN_PROGRESS и передавать ее соответствующему обработчику (TaskDispatcherComponent). Обработчик будет принимать десериализованный контекст запланированной задачи и исполнять ее в отдельном процессе. Ему доступны все модели и компоненты системы. Для определения статуса исполняемой задачи можно воспользоваться подходами Polling и LongPolling, а также организовать просмотр очереди своих задач отдельным отображением. Такой подход оказался более надежным и понятным, хоть и требует определенных архитектурных изменений в системе.

Печать (Ctrl+P)

Web-сервисы

Механизм Web-сервисов позволяет использовать «1С:Предприятие» как набор сервисов в сложных распределенных и гетерогенных системах, а также позволяет интегрировать «1С:Предприятие» с другими промышленными системами использованием сервисно-ориентированной архитектуры.

Добавление Web-сервиса

Для того чтобы добавить Web-сервис в дерево конфигурации, следует выделить ветку Общие – Web-сервисы и выполнить команду контекстного меню Добавить .
В результате выполнения команды будет открыто окно редактирования Web-сервиса.

На закладке Прочее окна редактирования Web-сервиса следует установить следующие параметры:
URI пространства имен – содержит URI пространства имен Web-сервиса. Каждый Web-сервис может быть однозначно идентифицирован по своему имени и URI пространству имен, которому он принадлежит.
● Пакеты XDTO – перечень пакетов XDTO, типы которых могут использоваться в качестве типов возвращаемого значения операций и типов параметров операций Web-сервиса.
Имя файла публикаций – имя файла описания Web-сервиса, который расположен на веб-сервере.
Для получения доступа к Web-сервису необходимо использовать адрес, который формируется следующим образом: <Имя хоста веб-сервера>/<Имя виртуального каталога>/ws/<Имя Web-сервиса> или <Имя хоста веб-сервера>/<Имя виртуального каталога>/ws/<Адрес Web-сервиса> .
Так, если виртуальный каталог имеет имя DemoWS , имя Web-сервиса в конфигураторе указано как ДемонстрацияРаботыWS, а в качестве адреса указано DemoWorkWS , то обращение к Web-сервису можно выполнять одновременно по двум адресам (для получения доступа с локальной машины):
http://localhost/DemoWS/ws/ДемонстрацияРаботыWS или http://localhost/DemoWS/ws/DemoWorkWS.
Кроме этого, на закладке содержится кнопка Модуль, которая позволяет открыть для редактирования модуль Web-сервиса.

Иерархическая структура Web-сервиса

Каждый Web-сервис, описываемый в дереве конфигурации, может содержать набор операций. Каждой операции должна соответствовать экспортируемая процедура, описанная в модуле Web-сервиса.


Описание Web-сервиса

В свою очередь, каждая операция может содержать набор параметров, имена которых должны соответствовать именам параметров процедуры, описывающей данную операцию.

Операции Web-сервиса

На закладке Операции выполняется добавление операции Web-сервиса. Редактирование свойств операции выполняется в палитре свойств.


Свойства операции Web-сервиса

Тип возвращаемого значения – тип значения, которое возвращает операция Web-сервиса. Может являться типом значения XDTO или типом объекта XDTO.
Возможно пустое значение – показывает, может ли возвращаемое значение принимать неопределенное значение.
В транзакции – показывает, будет ли выполняться код модуля Web-сервиса в транзакции или нет. Если свойство установлено, то при вызове Web-сервиса автоматически будет начата транзакция, а при завершении транзакция будет либо зафиксирована, либо произойдет откат транзакции (в зависимости от результатов выполнения). Если свойство не установлено, при начале исполнения модуля Web-сервиса транзакция начата не будет.
Имя процелуры – имя экспортной процедуры модуля Web-сервиса, которая будет выполнена при вызове данного свойства.
Режим управления блокировкой данных – указывает, какие блокировки будут использовать при доступе к данным.

Параметры операции

На закладке Операции для указанной операции нужно осуществить задание параметров операции Web-сервиса. Редактирование свойств параметра
выполняется в палитре свойств.


Свойства параметра операции

Тип значения – тип значения параметра операции Web-сервиса. Может являться типом значения XDTO или типом объекта XDTO.
Возможно пустое значение – показывает, может ли значение параметра операции принимать неопределенное значение.
Направление передачи – определяет направление передачи данных с помощью данного параметра. Возможные значения:
● Входной – означает, что параметр может использоваться только для передачи данных Web-сервису.
● Выходной – означает, что параметр может использоваться только для получения данных от Web-сервиса.
Входной – Выходной – означает, что параметр может использоваться как для передачи данных, так и для их получения от Web-сервиса.

Указание типов, определяемых системой

Чтобы в Web-сервисе воспользоваться типами, определяемыми системой 1С:Предприятие» (например, в параметрах и возвращаемом значении операций), нужно в конфигурации определить пакеты XDTO и для каждого пакета указать в его списке импортируемых пакетов (свойство Директивы импорта) набор пакетов платформы, в которые эти типы входят. URI пространства имен для указания типа содержится в статье синтакс-помощника по объекту данного типа.

Публикация Web-сервисов

Задача публикации сводится к размещению файла публикации в соответствующем каталоге. Для того, чтобы выполнить публикацию, следует выполнить команду меню “Администрирование – Публикация на веб-сервере… “.

В результате выполнения этой команды будет открыто окно, в котором осуществляется публикация информационной базы на локальном компьютере.

Внимание! Выполнение операции требует наличия прав администратора (для ОС Windows) или прав суперпользователя (для ОС Linux) на компьютере, на котором выполняется публикация

Основные настройки публикации

На закладке “Основные ” отображаются данные, необходимые для выполнения публикации.

Если публикация ранее не выполнялась, то значения полей (настройки) заполняется значениями по умолчанию (наименование выбирается из наименования информационной базы). Если требуется, измените эти настройки.
Если публикация уже выполнялась, то настройки выбираются по ранее указанным.
Если системой при открытии диалога с текущими настройками найдена публикация, но ее данные отличаются от данных настроек – выдается запрос на замену настроек.
Если публикация по настройкам не найдена, выдается предупреждение.

Выберите веб-сервер и укажите каталог, в который будет записан файл публикации.
Список веб-серверов формируется автоматически на основании установленных веб-серверов.

Имя публикации должно соответствовать правилам URL (стандарт RFC 1738).
Если выбран веб-сервер Apache 2.2 или Apache 2.4, то для имени каталога следует использовать US ASCII символы.

Примечание. При использовании веб-сервера Apache в диалоге настройки доступны для выбора обе версии веб-сервера. Следует учитывать, что настройки публикации для Apache 2.2 и Apache 2.4 несовместимы между собой. Поэтому необходимо правильно выбрать версию веб-сервера в диалоге.

Укажите необходимость публикации тонкого клиента и веб-клиента, а также Web- и HTTP-сервисов.

Если флажок “Публиковать стандартный интерфейс ODATA ” установлен, будет опубликован сервис ODATA, который позволяет считывать и изменять данные информационной базы с помощью HTTP-запросов.

На закладке “Web-сервисы ” установите флажок “Публиковать Web-сервисы ” и в таблице сформируйте список путем установки проставления флажков для тех Web-сервисов, которые нужно опубликовать.

Если флажок “Публиковать Web-сервисы по умолчанию” установлен, то при обновлении публикации выбранные web-сервисы будут опубликованы автоматически. В противном случае, web-сервисы будут отмечены как не публикуемые.

Если флажок “Публиковать Web-сервисы расширений по умолчанию” установлен, то при обновлении публикации web-сервисы, добавленные расширениями, будут опубликованы автоматически.

Итак. Код метода каждой ws-операции находится в модуле веб-сервиса, к которому принадлежит эта ws-операция.Модуль веб-сервиса исполняется только на Сервере.

Замечание 1 : нет смысла писать директивы компиляции &НаСервере, &НаКлиенте и другие.

На каждый вызов веб-операции создается отдельный сеанс с информационной базой, поэтому при каждом вызове веб-операции происходит инициализация параметров сеанса. Инициализация параметров сеанса происходит в модуле сеанса в процедуре "УстановкаПараметровСеанса".

Замечание 2 : не нагружайте эту процедуру лишними действиями.

Лично я в данное процедуре при первом вызове делаю инициализацию только самых часто используемых параметров сеанса. И только если нужны другие параметры сеанса, при повторном вызове, обрабатываю указанные параметры.

Процедура УстановкаПараметровСеанса(ИменаПараметровСеанса)

//суть изменений - получить сразу только важные параметры, а если нужны еще параметры воспользоваться подсистемой БСП

Если ИменаПараметровСеанса=Неопределено Тогда

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ ПЕРВЫЕ 1

|ИЗ

|Справочник.Пользователи КАК Пользователи

|ГДЕ

|Пользователи.ИдентификаторПользователяИБ = &ИдентификаторПользователяИБ";

ИдентификаторПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;

Запрос.Параметры.Вставить("ИдентификаторПользователяИБ ", ИдентификаторПользователяИБ);

РезультатПользователи = Запрос.Выполнить();

ВыборкаДетальныеЗаписи = Запрос.Выполнить().Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл

ПараметрыСеанса.ТекущийПользователь = ВыборкаДетальныеЗаписи.Ссылка;

КонецЦикла;

ПараметрыСеанса.ТекущийКонтрагент = ПараметрыСеанса.ТекущийПользователь.Контрагент;

Иначе

СтандартныеПодсистемыСервер.УстановкаПараметровСеанса(ИменаПараметровСеанса);

КонецЕсли;

КонецПроцедуры


Если вы читали статью 1С:Предприятие 8. Веб-сервисы. Реализация собственного веб-сервиса , то заметили что в дереве метаданных параметр ws-операции называется "Param", а в реализующем его методе называется "Параметр". Дело в том что наименование операндом в методе ws-операции не имеет значение, 1С подставляет операнды в том порядке в котором они указаны в дереве метаданных ws-операции. Например у нас есть операция Example1, в конфигураторе мы указали что операция имеет два параметра "param1" и "param2" и создали процедуру которая выводит "param2".

Если мы вызовем ws-операцию Example1 и передадим в качестве параметров param1=1, param2=2, то в результат получим 2.

Но если мы поменяем порядок операндов в конфигураторе:

То тот же самый вызов вернет 1.

Замечание 3 : после смены порядка параметров ws-операции, не забудьте поменять их порядок в заголовке функции, реализующей эту операцию.

Замечание 4 : в качестве операндов ws-операции можете использовать отличные от заданных в конфигураторе имена.

Если у части параметров ws-операции установлена галочка "Возможно пустое значение", то данный параметр может быть не указан при вызове, но тут есть несколько нюансов. При использовании клиента, например SoapClient вы не можете при передачи параметра просто взять и не указать параметр совсем. Например:

$a=$client->Plus2();


Эта строка вызовет ошибку " Неизвестная ошибка. Недостаточно параметров операции". То есть сам параметр надо передать, указав значение null:

$zz=array("Param"=>null);

$a=$client-> Plus2 ($zz);

Но тогда возникает вопрос, а как этот пустой параметр будет передан в 1С. Логично что программисту 1С захочется сделать в методе веб-операции следующее:

Функция Plus2(Параметр=0)

Возврат Параметр+2;

КонецФункции

То есть указать значение операнда в случае его отсутствия.

Теперь надо вызвать наш веб-операцию с пустым. Приведу пример xml сообщения soap с передачей значение null.


xsi:nil="true" - указывает, что данный параметр не имеет значение. Для того что бы можно было указать null дополнительно надо связать префикс xsi с пространством имен: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" .


Но если он сделает вызов такой ws-операции с пустым значением то получит сообщение об ошибке:

Soap:Client

Неизвестная ошибка.

по причине:

{WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено

по причине:

{WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено


Все потому, что переданное значение null преобразуется в значение 1с - "Неопределено". В этом можно убедиться если переписать процедуру так.

Функция Plus2(Параметр=0)

Если Параметр = Неопределено Тогда

Результат = 1;

Иначе

Результат = 2;

КонецЕсли;

Возврат Результат;

КонецФункции


Результатом будет - 1.

Замечание 5: нет смысла писать значение операнда ws-операции по умолчанию(Функция Plus2(Параметр=0) ). Для операндов, которые могут принимать пустое значение надо добавить проверку на равенство "Неопределено".


Замечание 6: При передачи в веб-операцию параметра строкового типа, строка из одного или нескольких пробелов обрезается до пустой строки.

Замечание 7: При передаче в веб-операцию параметра типа дата (datetime) с использованием формата с указанием на часовой пояс, время приводится к часовому поясу в котором находится платформа 1с. Например если операция имеет параметр "Дата" типа datetime, ПК на котором располагается 1с находится в часовом поясе +6, то при передаче в этот параметр значения "2012-09-14T00:00:00.000+02:00" в коде веб-операции данный параметр будет иметь значение "14.09.2012 4:00:00". Следовательно "+02:00" указывает на то, в каком поясе находится отправитель. Это позволит вам не задумываться о переводе времени при работе в нескольких часовых поясах.

Еще немного провеб-сервисы, их реализацию, тестирование и прочее можно прочесть тут.

Сегодня WEB сервисы используются практически повсеместно – именно они предоставляют нам информацию о рейсах самолетов и поездов, курсах валют и погоде. Неудивительно, что и 1С обладает возможностью создания собственных WEB сервисов, позволяющих выступать как в роли поставщика, так и потребителя. Данный механизм встроен в платформу «1С:Предприятие 8.3» и разработчики могут добавлять даже в типовую конфигурацию собственные объекты типа «WEB-сервисы». Их архитектура построена на наборе сервисов, позволяющих обмениваться информацией с другим программным обеспечением.

Создание веб-сервиса 1С

Одним из главных преимуществ WEB-сервисов 1С является отсутствие необходимости давать прямой доступ к данным ИБ. Правильно настроенный веб-сервис 1С позволяет другим приложениям пользоваться функциями извне. В таких случаях определять право пользования данными по заданным параметрам должна сама функция по прописанным разработчиком правилам.

Как создавать веб-сервис в 1С?

Чтобы определенная функция системы 1С стала доступна внешнему ПО, необходимо выполнить следующий алгоритм действий:

  1. Зайти в конфигурацию и в определенной ветке дерева добавить объект WEB-сервис;
  2. Описать все операции, которые сможет выполнять наш функционал. Описание функций производиться в модуле на встроенном в 1С языке;
  3. Добавить описание параметров функций веб-сервиса. Учтите, что типы данных описываются с учетом существующих типов механизма XDTO, появившегося в платформе версии 8.1;
  4. Опубликовать созданный WEB-сервис на сервере. Механизм, встроенный в платформу 1С, поддерживает следующие стандарты:
  • SSL/TLS
  • WS-I BP

Пример создания простого WEB-сервиса

Чтобы наиболее наглядно продемонстрировать работу механизма WEB-сервисов, создадим пример – функционал, определяющий длину введенной строки. Программное обеспечение передаст в качестве параметра запроса строку, а функция, описанная в 1С, вернет число символов. При создании нужно помнить, что публикация этого механизма даст возможность обращения к нему различного ПО. Так как не каждое ПО способно воспринимать кириллицу, будем называть объекты конфигурации, используя латинские знаки.

Открываем конфигуратор, находим в дереве ветку «WEB-сервисы» и добавляем новый сервис «wa_LengthString». Также необходимо на вкладке «Операции» добавить новую операцию. Назовем ее «CalcLengthString», в свойствах укажем тип возвращаемого значения – int или integer и создадим внутри нее параметр «InputString». Тип значения оставляем string.

Теперь необходимо прописать действие функции CalcLengthString в модуле WEB-сервиса. Для этого открываем свойства созданной функции и нажимаем кнопку в виде лупы справа, у поля ввода «Имя процедуры». 1С автоматически создаст функцию в модуле нашего WEB-сервиса и откроет его для того, чтобы мы описали действие CalcLengthString. Воспользуемся этим и напишем действие функции – определение длины вводимой строки.


Фактически на этом создание простейшего WEB-сервиса закончено. Теперь необходимо «выложить» этот сервис в общий доступ, чтобы стороннее ПО или другие системы 1С могли пользоваться данным функционалом.

Для того чтобы мы смогли опубликовать созданный веб-сервис с его функциональностью, нам необходимо иметь доступ на сайт. Перед тем как мы начнем публикацию сервиса, необходимо проверить имя файла в свойствах созданного модуля wa_LengthString. Оно должно быть понятное, простое и иметь расширение «1cws».


Теперь настало время публиковать созданный нами WEB-сервис на сервере. Эта возможность появилась в версии платформы 8.3 и многие компании уже поняли всю пользу этого функционала. Для того чтобы приступить к публикации, необходимо в конфигураторе открыть форму «Администрирование/Публикация на веб-сервере…».


В открывшемся окне нам необходима настройка Web сервисов 1С и заполнение определенных полей:

  • Имя. Обозначает папку на веб-сервере, в которой будет храниться описание нашего веб-сервиса. Будьте внимательны к регистрам, так как иногда серверы различают символы большого и малого регистра;
  • Веб-сервер. Необходимо выбрать сервер из установленных на компьютере;
  • Каталог. Вы должны выбрать путь к папке, где хранятся данные веб-сервера по настройке подключения. Используются исключительно латинские буквы;
  • Два признака типа «Булево». Первый нам пригодиться, если необходимо настроить доступ через веб-клиент к конфигурации. Для того чтобы опубликовать сервис 1С, необходимо поставить вторую отметку.

Остается лишь проверить, что у нужного WEB-сервиса установлена галка в первом столбце, и нажать на «Опубликовать».


Так как данный механизм еще достаточно новый, то вы можете столкнуться с ошибкой вида «Ошибка при выполнении файловой операции…». В этом случае вам нужно просто повторить нажатие «Опубликовать». В большинстве случаев это помогает, и вам покажется сообщение о том, что публикация веб-сервиса выполнена.

<имяСервера>.ru/<ИмяУказанногоКаталогаНаСервере>/ws/<НаименованиеФайла>.1cws?wsdl

В ответ на такой запрос адреса браузер должен отобразить структуру файла XML. Если же вы видите пустую страницу, ошибку или непонятные символы (проблемы с кодировкой), то нужно еще раз проверить все действия. Также не лишним будет убедиться, что сервер настроен верно, и у вас есть к нему доступ. После успешной публикации WEB-сервис 1С смогут использовать сторонние приложения.

Web-сервис - это средство интеграции, обеспечивающее концепцию сервисной архитектуры. То есть, система 1С может быть представлена как набор независимых сервисов для сторонних систем, и в свою очередь может выступать потребителем таких сервисов. Схема архитектуры:

Менеджер web-сервиса, представленный на схеме, закрывает следующие задачи:

  • управляет пулом соединений с информационными базами
  • поддерживает описание сервиса в формате WSDL (Web Services Description Language, язык описания веб-сервисов, основанный на XML)
  • реализует протокол SOAP (Simple Object Access Protocol - простой протокол доступа к объектам), обеспечивает сериализацию сообщений, вызов нужных web-сервисов

В конфигурации web-сервисы реализованы как общие объекты:

Для web-серивиса, специфицируется набор операций, каждая из которых может характеризоваться определенными параметрами для передачи данных:

Web-сервис работает с помощью XML, соответственно ему необходимо указать схему разметки; для этого web-сервис ссылается на пакет XDTO :

Вопрос 08.42 экзамена 1С:Профессионал по платформе. Менеджер WEB сервисов решает задачу:

  1. управление пулом соединений с информационными базами
  2. поддержка WSDL описания сервиса, реализация протокола SOAP
  3. поддержка работы WEB приложения
  4. верны ответы 1,2
  5. верны ответы 2,3
  6. верны ответы 1,2,3

Правильный ответ четвертый, работу web-приложения web-сервис не обеспечивает (см. выше его функции).

Вопрос 08.43 экзамена 1С:Профессионал по платформе. Объект конфигурации "WEB сервис" используется для:

  1. организации обращения к web-сервисам по статической ссылке
  2. экспорта функциональности данной информационной базы

Правильный ответ третий - web-сервис специфицирует некоторую функциональность, которая может быть доступна из вне данной базы.

Вопрос 08.44 экзамена 1С:Профессионал по платформе. Объект конфигурации "WSСсылка" используется для:

  1. организации динамического обращения к web-сервисам
  2. организации обращения к web-сервисам по статической ссылке
  3. экспорта функциональности данной информационной базы

Правильный ответ второй. WS-ссылка - это общий объект конфигурации, предназнасенный для доступа к сторонним веб-сервисам по статической ссылке. Ссылка состоит из модели данных, по сути пакета XDTO, и web-сервиса, с которого опубликована ссылка:

Вопрос 08.45 экзамена 1С:Профессионал по платформе. В случае если функция, реализующая операцию WEB сервиса, возвращает какое-либо значение. То такое значение определяется (при настройке соответствующего объекта конфигурации) как имеющее тип:

  1. Строка
  2. Число
  3. Булево
  4. элемент XML
  5. объект или значение XDTO
  6. верны ответы 1,2,3

Правильный ответ пятый.

Вопрос 08.48 экзамена 1С:Профессионал по платформе. В случае если функция, реализующая операцию WEB сервиса, принимает какое-либо значение в качестве параметра. То такое значение определяется (при настройке соответствующего объекта конфигурации) как имеющее тип:

  1. Строка
  2. Число
  3. Булево
  4. элемент XML
  5. объект или значение XDTO
  6. верны ответы 1,2,3

Правильный ответ аналогично пятый.

Вопрос 08.46 экзамена 1С:Профессионал по платформе. При обращении к WEB сервису по статической ссылке последовательность действий следующая:

  1. получение wsdl описания, настройка подключения (создание прокси), обращение к операции сервиса
  2. настройка подключения (создание прокси), обращение к операции сервиса
  3. обращение к операции сервиса

Правильный ответ второй - в случае статической ссылки, каждый раз получать wsdl описание не требуется.

Вопрос 08.47 экзамена 1С:Профессионал по платформе. При обращении к WEB сервису по динамической ссылке последовательность действий следующая:

  1. получение wsdl описания, настройка подключения (создание прокси), обращение к операции сервиса
  2. настройка подключения (создание прокси), обращение к операции сервиса
  3. обращение к операции сервиса

Правильный ответ первый.