воскресенье, 14 октября 2012 г.

1С:Предприятие 8. Веб-сервисы. Написание кода веб-сервиса



Содержание статей: 1С:Предприятие 8. Веб-сервисы
Предыдущая статья: 1С:Предприятие 8. Веб-сервисы. Реализация собственного веб-сервиса


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

Модуль веб-сервиса исполняется только на Сервере.
Замечание 1: нет смысла писать директивы компиляции &НаСервере, &НаКлиенте и другие.
-----------------
На каждый вызов веб-операции создается отдельный сеанс с информационной базой, поэтому при каждом вызове веб-операции происходит инициализация параметров сеанса. Инициализация параметров сеанса происходит в модуле сеанса в процедуре "УстановкаПараметровСеанса".
Замечание 2: не нагружайте эту процедуру лишними действиями.

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

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

//суть изменений - получить сразу только важные параметры, а если нужны еще параметры воспользоваться подсистемой БСП
Если ИменаПараметровСеанса=Неопределено Тогда
   Запрос = Новый Запрос;
   Запрос.Текст =
   "ВЫБРАТЬ ПЕРВЫЕ 1
   | Пользователи.Ссылка КАК Ссылка
   |ИЗ
   | Справочник.Пользователи КАК Пользователи
   |ГДЕ
   | Пользователи.ИдентификаторПользователяИБ = &ИдентификаторПользователяИБ";
   ИдентификаторПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
   Запрос.Параметры.Вставить("ИдентификаторПользователяИБ ", ИдентификаторПользователяИБ);  
   РезультатПользователи = Запрос.Выполнить();
   ВыборкаДетальныеЗаписи = Запрос.Выполнить().Выбрать();
   Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
      ПараметрыСеанса.ТекущийПользователь = ВыборкаДетальныеЗаписи.Ссылка;       
   КонецЦикла;
   ПараметрыСеанса.ТекущийКонтрагент = ПараметрыСеанса.ТекущийПользователь.Контрагент;
Иначе
   СтандартныеПодсистемыСервер.УстановкаПараметровСеанса(ИменаПараметровСеанса);
КонецЕсли;
КонецПроцедуры
-----------------

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


Если мы вызовем ws-операцию Example1 и передадим в качестве параметров param1=1, param2=2, то в результат получим 2.
Но если мы поменяем порядок операндов в конфигураторе:
Код веб-сервиса 1с

То тот же самый вызов вернет 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.


<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:uri="www.URI.com">
   <soapenv:Header/>
   <soapenv:Body>
      <uri:Plus2>
         <uri:Param xsi:nil="true"></uri:Param>
      </uri:Plus2>
   </soapenv:Body>
</soapenv:Envelope>

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

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


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Header/>
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>Неизвестная ошибка. {WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено
по причине:
{WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено</faultstring>
         <detail>Неизвестная ошибка. {WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено
по причине:
{WebСервис.WebService.Модуль(2)}: Преобразование значения к типу Число не может быть выполнено</detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>


Все потому, что переданное значение 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' указывает на то, в каком поясе находится отправитель. Это позволит вам не задумываться о переводе времени при работе в нескольких часовых поясах.
-----------------

Веб-сервисы как правило создают для обмена информацией с информационными системами разного происхождения. Перед программистом 1С возникает вопрос какие структуры XDTO стоит использовать. Например нужно на сайт из 1С передать информацию по какому либо товару. Есть два подхода: передача в виде объектов и передача в виде таблиц. При передаче в виде объектов вы создаете иерархическую структуру XDTO например:
На рисунке видно что имеется объект "Номенклатура", этот объект имеет поле "ЕдиницаИзмерения", которое имеет тип объекта "Единица измерения" и при выгрузке остатков через объект "Остатки номенклатуры" в свойстве "Массив" будет происходить передача всего объекта номенклатура и его остатка. То есть при каждой передаче передается довольное объемный объект Номенклатура, хотя она меняется довольно редко и при большом количестве номенклатуры (порядка 2000 при данной структуре) выгрузка бы просто не завершилась, т.к. хостинг ограничивает и объем передаваемых данных и время выполнения скрипта по передаче. Для ускорения передачи проще передавать массив [УИДНоменклатуры - Остаток]. В таком случае передается только уникальный идентификатор номенклатуры, по которому мы всегда сможем получить его свойства.
И у того и у другого способа есть свои достоинства и недостатки.
Достоинства объектного способа:

  • вы всегда получаете полный объем информации и нет необходимости в синхронизации объектов по идентификаторам;
  • удобочитаемость - вы всегда видите наименование объекта и его свойства. а не просто идентификатор.
Недостатки объектного способа:
  • при изменении структуры приходится переписывать код всех процедур в которых идет работа с этим объектом;
  • большой объем передаваемых данных;
  • для формирования объекта необходимо получать все его свойства из запроса или лругим способом.
Достоинства табличного подхода:
  • небольшой объем передаваемых данных;
  • при изменении свойств объекта достаточно изменить только одну процедуру п синхронизации этого объекта;
  • для передачи ссылки на объект нет необходимости получать все его свойства в каждой ws-операции.
Недостатки табличного подхода:
  • трудно читать soap-сообщения;
  • при выгрузке данных ссылок на объекты, надо продумать еще и операции по получению свойств этих объектов и их своевременную синхронизацию(например при смене наименования товара его надо тут же выгрузить на сайт);


Замечание 8: при проектировании структуры выгрузки веб-сервиса не пренебрегайте вопросами объема передаваемых данных и времени их передачи, т.к. передача через веб-сервисы действительно проходит долго. Приведу пример своего опыта. Я хотел узнать максимальный объем передаваемых данных и создал веб сервис который передавал массив объектов XDTO. Один объект занимал примерно 740 байт (это довольно мало, т.к. не забывайте что в этот объем входят и длинна тегов soap сообщения). При канале в 5 Мбит/с смог передать 150 тысяч таких объектов и все это занимало чуть больше 100 Мб. И эта передача выполнялась 3,5 минуты. После 100 Мбайт soap-клиент (souapUI) просто завис. При использовании платного хостинга данная выгрузка бы прервалась на 2 минуте (обычно такое ограничения ставят хостеры на время выполнения скрипта).
-----------------

Замечание 9: для уменьшения передаваемых данных используйте короткие названия свойств объектов XDTO, т.к. они используются в названиях тегов (каждый тег повторяется два раза при открытии и закрытии тега). Используется кодировка UTF8, а это 2 байта на символ.
-----------------

Замечание 10: Указание  типа dateTime без символа "T" например: "2012-09-14 15:00:00" не вызывает ошибки, но отбрасывает часы,минуты и секунды. То есть система примет эту дату как "2012-09-14".
-----------------

Замечание 11: в качестве URI пространства имен можно указать не только ссылку, но и строки не являющие ссылками, даже в кириллице и даже цифры, но это совсем не означает что не происходит проверок этого поля. В это поле, например, нельзя указать "http://tcp://". Но ошибку выдаст уже веб-сервер

7 комментариев:

  1. Добрый день! Подскажите, пожалуйста, можно ли из модуля веб-сервиса записывать документы в базу данных?

    ОтветитьУдалить
    Ответы
    1. Да, можно. Это обычный модуль который работает нс стороне сервера.

      Удалить
  2. Анонимный28 апреля, 2017 19:10

    Здравствуйте. А почему в модуле веб сервиса невозможно обратиться к экспортной процедуре объекта
    СсылкаОбъект = Документы.ПоступлениеТоваров.ПолучитьСсылку(НовыйGUID).получитьОбъект();
    СсылкаОбъект.Печать("Накладная",,ложь);


    ...

    {WebСервис...Модуль(29)}: Метод объекта не обнаружен (Печать)

    ОтветитьУдалить
    Ответы
    1. В процедуре веб сервиса можно так делать. Проверьте что НовыйGUID типа УникальныйИдентификатор.

      Удалить
  3. Добрый вечер. В модуле веб-сервиса есть функция
    Платежка = Документы.ПлатежноеПоручение.ПолучитьСсылку(ГУИД);
    ПлатежкаОбъект = Платежка.ПолучитьОбъект();
    ГУИД типа УникальныйИдентификатор. При попытке получить объект выдает ошибку:
    Ошибка инициализации библиотеки модулей
    по причине:
    {ОбщийМодуль.ОбщегоНазначения.Модуль(9591,2)}: Переменная не определена (ГлавныйИнтерфейс)
    Код ошибки: Client

    ОтветитьУдалить
    Ответы
    1. В первую очередь надо глянуть строку 9591 модуля ОбщегоНазначения. Понять где инициализируется ГлавныйИнтерфейс. Лично у меня есть предположение, что это глобальная переменная, которая определена в модуле оправляемого или обычного приложения, которые не вызываются при вызове веб сервиса.

      Удалить
    2. Спасибо за наводку)

      Удалить