Введение в SOAP. Пишем SOAP клиент-серверное приложение на PHP

Вообще сегодня есть стандартные протоколы обмена XML данными:

  • XML-RPC – вы передаете пакет и указываете, какой метод на сервере хотите вызвать.
  • REST - есть некие объекты на сервере. Каждый объект характеризуется каким-то идентификатором. У каждого элемента свой url. С любым элементов можно сделать: insert, delete, update, select. Вы просто посылаете нужный запрос на сервер (например, вставить такой-то элемент). Обмен клиент-сервер базируется либо на JSON, либо на XML.

Именно на RPC базируется SOAP (сервис ориентированная архитектура, набор слабосвязанных сервисов, взаимодействующих друг с другом). Главное достоинство RPC - небольшое количество сетевых ресурсов (точек входа) и много задействованных методов. Несмотря на это достоинство, у RPC - это устаревший протокол, у которого ряд недостатков:

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

Все эти недостатки были решены в XML Schema. Это промышленный стандарт описания XML документа. Т.е. это способ моделирования произвольных данных. XML схема может описывать модель (отношения между элементами и атрибутами, и их структура), типы данных (характеризует типы данных) и словарь (названия элементов и атрибутов).

Исходя из всех недостатков XML-RPC создали протокол SOAP.

SOAP (Simle Object Access Protocol) - протокол доступа к объекту (к точке входа). Сегодня это основной промышленный стандарт построения распределенных приложений.

Он представляет собой расширения языка XML-RPC. Т.е. он построен по принципу: 1 точка входа и любые методы. Сам протокол в плане транспорта (как передать данные) дает широкий выбор: SMTP, FTP, HTTP, MSMQ.

SOAP лежит в основе реализации XML веб-сервисов (XML веб служб). Недостаток SOAP - сложен в изучении.

SOAP базируется на обмене сообщениями между клиентом и сервером (синхронно и асинхронно). Каждое сообщение несет информацию о данных (какие данные передаются-получаются). SOAP заранее описывает всю структуру сообщения с помощью XML схем: что должно быть в сообщении, как оно будет передаваться. Это дает возможность, не зная сервер, понять, что там происходит, и дает возможность серверу проверить, для него ли это сообщение.

XML схема

Задача схемы - описать структуру данных, т.е. что у нас есть. Все данные делятся на простые и сложные типы (скаляры и структуры). Простой тип (строка, число, boolean, дата) никогда внутри ничего содержать не будет. А структура (объект) может содержать свойства.

Основные операции SOAP

  • Не только простой обмен информацией клиент-сервер. Но и автоматическое распознавание сервера и поиск этого сервера, т.е. клиент может даже ничего не знать про сервер. Т.е. клиент сначала выполняет поиск сервера, найдет подходящие службы, поймет какие там методы, что на сервера есть, и произведет его вызов.
  • Сервер производит публикацию своей информации (расположение, какие методы поддерживает), чтобы клиент нашел этот сервер. Публикация происходит в UDDI каталог.

Структура SOAP сообщений:

  • SOAP Envelope (конверт) - сюда входит все сообщение. Состоит из заголовка и тела.
  • SOAP Header (заголовок) - дополнительная информация (авторизация, например).
  • SOAP Body (тело) - само сообщение.
  • SOAP Fault (ошибка) - способ передачи ошибки от сервера к клиенту.

WSDL

WSDL (Web Services Description Language) - язык описания веб служб. Применяется в SOAP. Это некий докуент, который описывает все: какие пространства имен использовались, какие схемы данных использовались, какие типы сообщений сервер ждет от клиента, какие конверты к какому методу принадлежат, какие методы вообще есть, на какой адрес отправлять и т.д. Собственно, WSDL и есть веб сервис. Достаточно клиенту изучить содержимое этого документа, он уже знает о сервере все.

Любой сервер должен публиковать WSDL.

WSDL состоит из блоков:

  • Определение самой службы, т.е. точки входа, указывается порт.
  • Формат методов. Происходит привязка точки входа к операциям, т.е. какие методы поддерживает. Указывается тип вызова, способ передачи. Внутри каждого метода происходит объяснение - в каком виде передаются данные - в виде SOAP.
  • Привязка методов к сообщению.
  • Описание самих сообщений.

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

Введение

Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется RPC (Remote Procedure Calling – удаленный вызов процедур). В качестве примеров можно привести технологии CORBA, а для Java – RMI (Remote Method Invoking – удаленный вызов методов). И все вроде в них хорошо, особенно в CORBA, т.к. с ней можно работать на любом языке программирования, но чего-то все же не хватало. Полагаю, что минусом CORBA является то, что она работает через какие-то свои сетевые протоколы вместо простого HTTP, который пролезет через любой firewall. Идея веб-сервиса заключалась в создании такого RPC, который будет засовываться в HTTP пакеты. Так началась разработка стандарта. Какие у этого стандарта базовые понятия:
  1. SOAP . Прежде чем вызвать удаленную процедуру, нужно этот вызов описать в XML файле формата SOAP. SOAP – это просто одна из многочисленных XML разметок, которая используется в веб-сервисах. Все, что мы хотим куда-то отправить через HTTP, сначала превращается в XML описание SOAP, потом засовывается в HTTP пакет и посылается на другой компьютер в сети по TCP/IP.
  2. WSDL . Есть веб-сервис, т.е. программа, методы которой можно удаленно вызывать. Но стандарт требует, чтобы к этой программе прилагалось описание, в котором сказано, что «да, вы не ошиблись – это действительно веб-сервис и можно у него вызвать такие-то такие-то методы». Такое описание представляется еще одним файлом XML, который имеет другой формат, а именно WSDL. Т.е. WSDL – это просто XML файл описания веб-сервиса и больше ничего.
Почему так кратко спросите вы? А по подробней нельзя? Наверное можно, но для этого придется обратиться к таким книгам как Машнин Т. «Web-сервисы Java». Там на протяжении первых 200 страниц идет подробнейшее описание каждого тега стандартов SOAP и WSDL. Стоит ли это делать? На мой взгляд нет, т.к. все это на Java создается автоматически, а вам нужно лишь написать содержимое методов, которые предполагается удалено вызывать. Так вот, в Java появился такой API, как JAX-RPC. Если кто не знает, когда говорят, что в Java есть такой-то API, это означает, что есть пакет с набором классов, которые инкапсулируют рассматриваемую технологию. JAX-RPC долго развивался от версии к версии и в конечном итоге превратился в JAX-WS. WS, очевидно, означает WebService и можно подумать, что это простое переименование RPC в популярное нынче словечко. Это не так, т.к. теперь веб-сервисы отошли от первоначальной задумки и позволяют не просто вызывать удаленные методы, но и просто посылать сообщения-документы в формате SOAP. Зачем это нужно я пока не знаю, вряд ли ответ здесь будет «на всякий случай, вдруг понадобится». Сам бы хотел узнать от более опытных товарищей. Ну и последнее, далее появился еще JAX-RS для так называемых RESTful веб-сервисов, но это тема отдельной статьи. На этом введение можно заканчивать, т.к. далее мы будем учиться работать с JAX-WS.

Общий подход

В веб-сервисах всегда есть клиент и сервер. Сервер – это и есть наш веб-сервис и иногда его называют endpoint (типа как, конечная точка, куда доходят SOAP сообщения от клиента). Нам нужно сделать следующее:
  1. Описать интерфейс нашего веб-сервиса
  2. Реализовать этот интерфейс
  3. Запустить наш веб-сервис
  4. Написать клиента и удаленно вызвать нужный метод веб-сервиса
Запуск веб-сервиса можно производить разными способами: либо описать класс с методом main и запустить веб-сервис непосредственно, как сервер, либо задеплоить его на сервер типа Tomcat или любой другой. Во втором случае мы сами не запускаем новый сервер и не открываем еще один порт на компьютере, а просто говорим контейнеру сервлетов Tomcat, что «мы написали тут классы веб-сервиса, опубликуй их, пожалуйста, чтобы все, кто к тебе обратиться, могли нашим веб-сервисом воспользоваться». В независимости от способа запуска веб-сервиса, клиент у нас будет один и тот же.

Сервер

Запустим IDEA и создадим новый проект Create New Project . Укажем имя HelloWebService и нажмем кнопку Next , далее кнопку Finish . В папке src создадим пакет ru.javarush.ws . В этом пакете создадим интерфейс HelloWebService: package ru. javarush. ws; // это аннотации, т.е. способ отметить наши классы и методы, // как связанные с веб-сервисной технологией import javax. jws. WebMethod; import javax. jws. WebService; import javax. jws. soap. SOAPBinding; // говорим, что наш интерфейс будет работать как веб-сервис @WebService // говорим, что веб-сервис будет использоваться для вызова методов @SOAPBinding (style = SOAPBinding. Style. RPC) public interface HelloWebService { // говорим, что этот метод можно вызывать удаленно @WebMethod public String getHelloString (String name) ; } В этом коде классы WebService и WebMethod являются так называемыми аннотациям и ничего не делают, кроме как помечают наш интерфейс и его метод, как веб-сервис. Это же относится и к классу SOAPBinding . Разница лишь в том, что SOAPBinding – это аннотация с параметрами. В данном случае используется параметр style со значением, говорящим, что веб-сервис будет работать не через сообщения-документы, а как классический RPC, т.е. для вызова метода. Давайте реализуем логику нашего интерфейса и создадим в нашем пакете класс HelloWebServiceImpl . Кстати, замечу, что окончание класса на Impl – это соглашение в Java, по которому так обозначают реализацию интерфейсов (Impl – от слова implementation, т.е. реализация). Это не требование и вы вольны назвать класс как хотите, но правила хорошего тона того требуют: package ru. javarush. ws; // таже аннотация, что и при описании интерфейса, import javax. jws. WebService; // но здесь используется с параметром endpointInterface, // указывающим полное имя класса интерфейса нашего веб-сервиса @WebService (endpointInterface = "ru.javarush.ws.HelloWebService" ) public class HelloWebServiceImpl implements HelloWebService { @Override public String getHelloString (String name) { // просто возвращаем приветствие return "Hello, " + name + "!" ; } } Запустим наш веб-сервис как самостоятельный сервер, т.е. без участия всяких Tomcat и серверов приложений (это тема отдельного разговора). Для этого в структуре проекта в папке src создадим пакет ru.javarush.endpoint , а в нем создадим класс HelloWebServicePublisher с методом main: package ru. javarush. endpoint; // класс, для запуска веб-сервера с веб-сервисами import javax. xml. ws. Endpoint; // класс нашего веб-сервиса import ru. javarush. ws. HelloWebServiceImpl; public class HelloWebServicePublisher { public static void main (String. . . args) { // запускаем веб-сервер на порту 1986 // и по адресу, указанному в первом аргументе, // запускаем веб-сервис, передаваемый во втором аргументе Endpoint. publish ("http://localhost:1986/wss/hello" , new HelloWebServiceImpl () ) ; } } Теперь запустим этот класс, нажав Shift+F10 . В консоли ничего не появится, но сервер запущен. В этом можно убедиться набрав в браузере строку http://localhost:1986/wss/hello?wsdl . Открывшаяся страница, с одной стороны, доказывает, что у нас на компьютере (localhost) запустился веб-сервер (http://) на порту 1986, а, с другой стороны, показывает WSDL описание нашего веб-сервиса. Если вы остановите приложение, то описание станет недоступно, как и сам веб-сервис, поэтому делать этого не будем, а перейдем к написанию клиента.

Клиент

В папке проекта src создадим пакет ru.javarush.client , а в нем класс HelloWebServiceClient с методом main: package ru. javarush. client; // нужно, чтобы получить wsdl описание и через него // дотянуться до самого веб-сервиса import java. net. URL; // такой эксепшн возникнет при работе с объектом URL import java. net. MalformedURLException; // классы, чтобы пропарсить xml-ку c wsdl описанием // и дотянуться до тега service в нем import javax. xml. namespace. QName; import javax. xml. ws. Service; // интерфейс нашего веб-сервиса (нам больше и нужно) import ru. javarush. ws. HelloWebService; public class HelloWebServiceClient { public static void main (String args) throws MalformedURLException { // создаем ссылку на wsdl описание URL url = new URL ("http://localhost:1986/wss/hello?wsdl" ) ; // Параметры следующего конструктора смотрим в самом первом теге WSDL описания - definitions // 1-ый аргумент смотрим в атрибуте targetNamespace // 2-ой аргумент смотрим в атрибуте name QName qname = new QName ("http://ws.сайт/" , "HelloWebServiceImplService" ) ; // Теперь мы можем дотянуться до тега service в wsdl описании, Service service = Service. create (url, qname) ; // а далее и до вложенного в него тега port, чтобы // получить ссылку на удаленный от нас объект веб-сервиса HelloWebService hello = service. getPort (HelloWebService. class ) ; // Ура! Теперь можно вызывать удаленный метод System. out. println (hello. getHelloString ("JavaRush" ) ) ; } } Максимум комментариев по коду я дал в листинге. Добавить мне нечего, поэтому запускаем (Shift+F10). Мы должны в консоли увидеть текст: Hello, JavaRush! Если не увидели, то видимо забыли запустить веб-сервис.

Заключение

В данном топике был представлен краткий экскурс в веб-сервисы. Еще раз скажу, что многое из того, что я написал – это мои догадки по поводу того, как это работает, и поэтому мне не стоит сильно доверять. Буду признателен, если знающие люди меня поправят, ведь тогда я чему-нибудь научусь. UPD.

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

Вступление

Рассматривать будем только ситуацию, когда есть сторонний web-сервис и стоит задача наладить обмен данными.

Строение сервиса описывается в файле WSDL (англ. Web Services Description Language)

Файл чаще всего доступен по ссылке, где находится точка входа в сам web-сервис. Я написал «чаще всего», так как бывают исключения. Например, Web-сервис на базе SAP не публикует wsdl и его можно получить только выгрузив из самого приложения.

И так, у нас есть описание web-сервиса, логин, пароль. Давайте подключимся.

// Определяем настройки URLПространстваИменСервиса = "http://Somesite.ru"; ИмяПользователя = "TestUser"; Пароль = "q1w2e3"; МестоположениеWSDL = "https://Somesite.ru/WebService/Some?wsdl"; ИмяСервиса = "SomeServiceName"; ИмяТочкиПодключения = "SomeService_Port"; // Создаем подключение SSL = Новый ЗащищенноеСоединениеOpenSSL(); WSОпределение = Новый WSОпределения(МестоположениеWSDL,SSL); WSПрокси = Новый WSПрокси(WSОпределение, URLПространстваИменСервиса, ИмяСервиса, ИмяТочкиПодключения,SSL); WSПрокси.Пользователь = ИмяПользователя; WSПрокси.Пароль = Пароль;

Отлично! Мы подключились к web-сервису! По идее это основа любого варианта обмена, так как позволяет создавать объект структуры данных на основании wsdl, а работать с таким объектом одно удовольствие.

Рассмотрим XML который нам выдает SoapUI

357 121212 M 19900111 Mercedes GLS Audi TT

Теперь опишем его программно

// Создаем объект и наполняем его данными СвояФабрикаXDTO = WSОпределение.ФабрикаXDTO; КорневойТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "SUBMISSION"); КорневойОбъект = СвояФабрикаXDTO.Создать(КорневойТип); КорневойОбъект.ID = "4356"; КлиентТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "CUSTOMER"); КлиентОбъект = СвояФабрикаXDTO.Создать(КлиентТип); КлиентОбъект.CLIENT_ID = "121212"; КлиентОбъект.SEX = "M"; // F - женский, M - мужской КлиентОбъект.CLIENT_BIRTHDAY = "19900111"; // Автомобили клиента АвтоТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "CARS"); АвтоОбъект = СвояФабрикаXDTO.Создать(АвтоТип); АвтоОбъект.CLASS = "Mercedes"; АвтоОбъект.MODEL = "GLS"; КлиентОбъект.CARS.Добавить(АвтоОбъект); АвтоОбъект = СвояФабрикаXDTO.Создать(АвтоТип); АвтоОбъект.CLASS = "Audi"; АвтоОбъект.MODEL = "TT"; КлиентОбъект.CARS.Добавить(АвтоОбъект); КорневойОбъект.CUSTOMER.Добавить(КлиентОбъект);

Данные успешно заполнены. Теперь нужно их отправить.

В этот самый момент и возникает множество нюансов. Попробуем рассмотреть каждый.

Рецепт 1. Отправляем XDTO-объект целиком

Результат = WSПрокси.AddCustomers(КорневойОбъект);

Остается лишь обработать результат, который нам вернул сервис и на этом всё. Согласитесь, что это очень удобно!

Но на практике не всегда бывает так. Например 1с не ладит с префиксацией определенных тэгов внутри xml, когда пространство имен корнеового тэга отличается от пространства дочерних. В таких случаях приходится собирать soap вручную. Так же приходилось сталкиваться с web-сервисами, которые в качестве параметра ждут xml в чистом виде. Маразм, но все же делается это не слишком сложно.

Рецепт 2. Отправляем чистый xml в качестве параметра

ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина); МойXML = Новый ЗаписьXML; МойXML.УстановитьСтроку(ПараметрыЗаписиXML); МойXML.ЗаписатьОбъявлениеXML(); СвояФабрикаXDTO.ЗаписатьXML(МойXML, КорневойОбъект); СтрокаXML = МойXML.Закрыть(); Если УдалитьОписаниеПространстваИмен Тогда Попытка ПервыйТэгВСтроке = СтрПолучитьСтроку(СтрокаXML,2); ИмяКорневогоТэга = КорневойОбъект.Тип().Имя; СтрокаXML = СтрЗаменить(СтрокаXML, ПервыйТэгВСтроке, "<"+ИмяКорневогоТэга+">"); Исключение //ОписаниеОшибки() КонецПопытки; КонецЕсли; Результат = WSПрокси.AddCustomers(СтрокаXML);

Если не удалять пространство имен, которое 1с добавляет по умолчанию, то стало больше всего на 5 строк кода. Чаще всего я заворачиваю преобразование xml в функцию, так как обычно вызываем более одного метода.

Рецепт 3. Отправляем через нативный HTTPЗапрос.

СтрокаSOAP = " | | |" +СтрокаXML+ " | |"; // Описываем заголовки HTTP-запроса Заголовки = Новый Соответствие; Заголовки.Вставить("Content-Type", "text/xml;charset=UTF-8"); Заголовки.Вставить("SOAPAction", "http://sap.com/xi/WebService/soap1.1"); Заголовки.Вставить("Authorization", "Basic "+ПолучитьBase64ЗаголовокАвторизации(ИмяПользователя, Пароль)); // ВНИМАНИЕ!!! // Нельзя заполнять программно следующие заголовки, так как это приводит к ошибке // Платформа сама правильно их заполнит //Заголовки.Вставить("Accept-Encoding", "gzip,deflate"); //Заголовки.Вставить("Content-Length", Формат(СтрДлина(СтрокаSOAP),"ЧГ=")); // длина сообщения //Заголовки.Вставить("Host", "Somesite.ru:8001"); //Заголовки.Вставить("Connection", "Keep-Alive"); //Заголовки.Вставить("User-Agent", "Apache-HttpClient/4.1.1 (java 1.5)"); // Подключаемся к сайту. Соединение = Новый HTTPСоединение("Somesite.ru/WebService/Some",ИмяПользователя, Пароль,SSL, Ложь); // Адрес должен быть без https:// // Получаем текст корневой страницы через POST-запрос. HTTPЗапрос = Новый HTTPЗапрос("/GetCustomer", Заголовки); HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаSOAP); Результат = Соединение.ВызватьHTTPМетод("POST", HTTPЗапрос);

В этом варианте нам придется собрать soap вручную. По сути мы просто оборачиваем xml из рецепта 2 в оболочку soap, где в зависимости от требований web-сервиса мы можем менять наш soap как душе угодно.

Далее описываем заголовки согласно документации. Некоторые сервисы спокойно прожуют наш запрос и без заголовков, тут надо смотреть конкретный случай. Если вы не знаете какие заголовки прописывать, то самый простой способ это подглядеть запрос в SoapUI переключившись во вкладку RAW.

Функция получения Base64 строки выглядит так (подсмотрел ):

Функция ПолучитьBase64ЗаголовокАвторизации(ИмяПользователя, Пароль) КодировкаФайла = КодировкаТекста.UTF8; ВременныйФайл = ПолучитьИмяВременногоФайла(); Запись = Новый ЗаписьТекста(ВременныйФайл, КодировкаФайла); Запись.Записать(ИмяПользователя+":"+Пароль); Запись.Закрыть(); ДвДанные = Новый ДвоичныеДанные(ВременныйФайл); Результат = Base64Строка(ДвДанные); УдалитьФайлы(ВременныйФайл); Результат = Сред(Результат,5); Возврат Результат; КонецФункции

Есть важный момент. При работе с HTTPСоединение указывайте адрес без указания протоколов «http://» и «https://», иначе рискуете потратить время на поиск не очевидной ошибки.

Рецепт 4. Отправляем через WinHttpRequest

WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1"); WinHttp.Option(2,"UTF-8"); WinHttp.Option(4, 13056); //intSslErrorIgnoreFlag WinHttp.Option(6, true); //blnEnableRedirects WinHttp.Option(12, true); //blnEnableHttpsToHttpRedirects WinHttp.Open("POST", "https://Somesite.ru/WebService/Some/GetCustomer", 0); WinHttp.SetRequestHeader("Content-type", "text/xml"); WinHttp.SetCredentials(ИмяПользователя, Пароль, 0); WinHttp.Send(СтрокаSOAP); WinHttp.WaitForResponse(15); XMLОтвет = WinHttp.ResponseText();

Здесь по сути тоже самое, что и в предыдущем варианте, но работаем с COMОбъектом. Строку соединения указываем полностью, вместе с протоколом. Особое внимание следует уделить только флагам игнорирования ошибок SSL-сертификатов. Они нужны, если мы работаем по SSL, но без определенного сертификата, так как создать новое защищенное соединение в таком варианте не предоставляется возможным (или я не умею как). В остальном механизм схож с предыдущим.

Так же помимо "WinHttp.WinHttpRequest.5.1" можно использовать "Microsoft.XMLHTTP", "Msxml2.XMLHTTP", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0", если вдруг не взлетит на WinHttp. Методы практически такие же, только количество параметров другое. Подозреваю, что один из этих вариантов и зашит внутри объекта 1c HTTPЗапрос.

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

Обработка результата

В рецепте 1 мы чаще всего получаем готовый XDTO-объект и работаем с ним как со структурой. Во всех остальных случаях можно преобразовывать xml-ответ в XDTO

Если Результат.КодСостояния = 200 Тогда ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(Результат.ПолучитьТелоКакСтроку()); ОбъектОтвет = СвояФабрикаXDTO.ПрочитатьXML(ЧтениеXML); Сообщить(ОбъектОтвет.Body.Response.RESPONSE_ID); Сообщить(ОбъектОтвет.Body.Response.RESPONSE_TEXT); КонецЕсли;

Тут все просто.

Вместо заключения

1. Начинайте работу с web-сервисами с программы SoapUI. Она предназначена для таких работ и позволит быстрее понять как работает тот или иной сервис. Для освоения есть статья

2. Если вы обмениваете с сервисом по незащищенному каналу http и возникает вопрос в том что именно отправляет 1с в своих сообщениях, то можно воспользоваться снифферами трафика такими как Wireshark , Fiddler , и другие. Проблема возникнет только если используете ssl-соединение.

3. Если все же web-сервис общается по https, то ставим на удаленной машине (любой, главное не на своей) сервер Nginx , к которому мы и будем обращаться, а он в свою очередь запакует все в https и перешлет куда нужно ( reverse proxy) и в стандартный конфиг добавляем:

Server { listen 0.0.0.0:8080; server_name MyServer; location ~ .* { proxy_pass https://Somesite.ru:8001; proxy_set_header Host $host; proxy_set_header Authorization "Basic "; proxy_pass_header Authorization; } }

5. Если аутентификация предполагает использование Cookie, то нашлась следующая

P.S. Если у вас появились вопросы, предложения по улучшению кода, есть собственные рецепты, отличные от описанных, вы нашли ошибки или считаете, что автор "ниправ" и ему "не место в 1с", то пишите комментарии, и мы все обсудим.

Валентин Колесов
разработчик красноярского отделения санкт-петербургской компании "Астрософт", сертифицированный специалист Microsoft (MCSD, MCSE, MCDBA)
[email protected]

Демонстрация работы SOAP на примере написания Web-сервера

Что такое SOAP

Широко распространенные в настоящее время технологии удаленного вызова методов (DCOM, CORBA/IIOP и RMI) довольно сложны в настройке и организации взаимодействия. Это влечет за собой трудности в эксплуатации и функционировании распределенных систем (проблемы безопасности, неудобства транспорта через брандмауэры и т. д.). Многие проблемы удалось решить благодаря созданию SOAP (Simple Object Access Protocol, простой протокол доступа к объектам), простого протокола, основанного на XML и служащего для обмена сообщениями в распределенных средах (WWW). Протокол предназначен для создания Web-сервисов и удаленного вызова методов. SOAP можно использовать в сочетании с разными транспортными протоколами, включая HTTP, SMTP и др.

Что такое Web-сервисы

Web-сервисами мы называем активный контент, реализующий некоторую функциональность, и данные, расположенные на Web-серверах и предоставляемые для использования внешним приложениям. Web-сервисы полностью независимы от языка и платформы реализации. Внешние приложения работают с сервисами посредством стандартных протоколов и форматов данных. Технология Web-сервисов является краеугольным камнем программной модели Microsoft .NET.

Для демонстрации возможностей SOAP в статье использована недавно вышедшая реализация SOAP Toolkit версии 2.0 производства Microsoft. Следует заметить, что текущая версия Toolkit заметно отличается от предыдущей (Microsoft SOAP Toolkit for Visual Studio 6.0) и от бета-версии SOAP Toolkit 2.0.

Объектная модель SOAP Toolkit предоставляет как низкоуровневые, так и высокоуровневые интерфейсы (SOAPClient, SOAPServer), скрывающие от программиста всю "внутреннюю кухню" - разбор и формирование пакетов, вызов методов и т. п. С помощью этих интерфейсов можно весьма элегантным образом использовать Web-сервисы в разрабатываемых приложениях. Объект SOAPClient выступает в роли посредника (proxy), предоставляющего интерфейс Web-сервиса и позволяющего работать с ним как с обычным COM-объектом (рис. 1).

  1. Клиентское приложение создает экземпляр объекта SOAPClient.
  2. SOAPClient читает файлы описания методов Web-сервиса (на языках WSDL и Web Services Meta Language, WSML). Эти файлы могут храниться и на стороне клиента.
  3. Клиентское приложение, используя возможности позднего связывания методов объекта SOAPClient, вызывает метод сервиса. SOAPClient формирует пакет запроса (SOAP Envelope) и отправляет его на сервер. Можно применить любой транспортный протокол, но, как правило, используется HTTP.
  4. Серверное приложение Listener (это может быть ISAPI-приложение или ASP-страница) принимает пакет, создает объект SOAPServer и передает ему пакет запроса. Помимо этого Listener обрабатывает HTTP-пакеты от клиента, отправляет клиенту пакеты с результатом работы сервиса, обрабатывает ошибки и использует функциональность SOAP-объектов.
  5. SOAPServer читает описание Web-сервиса, загружает описание и пакет запроса в деревья XML DOM.
  6. SOAPServer вызывает метод объекта или приложения, реализующего сервис.
  7. Результаты выполнения метода или описание ошибки конвертируются объектом SOAPServer в пакет ответа и отправляются клиенту.
  8. Объект SOAPClient проводит разбор принятого пакета и возвращает клиентскому приложению результаты работы сервиса или описание возникшей ошибки.

WSDL-файл - это документ в формате XML, описывающий методы, предоставляемые Web-сервисом, а также параметры методов, их типы, названия и местонахождение сервиса Listener. Мастер SOAP Toolkit автоматически генерирует этот документ, фрагмент которого приведен ниже:

Тег Envelope должен быть корневым элементом пакета. Элемент Header не обязателен, а Body должен присутствовать и быть прямым потомком элемента Envelope. В случае ошибки выполнения метода сервер формирует пакет, содержащий в теге Body элемент Fault, который содержит подробное описание ошибки.

Если вы пользуетесь высокоуровневыми интерфейсами SOAPClient, SOAPServer, то вам не придется вдаваться в тонкости формата пакета, но при желании можно воспользоваться низкоуровневыми интерфейсами или же вообще создать пакет "вручную", используя любой язык программирования.

Объектная модель SOAP Toolkit дает возможность работать с объектами низкоуровневого API:

  • SoapConnector - обеспечивает работу с транспортным протоколом для обмена SOAP-пакетами.
  • SoapConnectorFactory - обеспечивает метод создания коннектора для транспортного протокола, указанного в WSDL-файле (тег).
  • SoapReader - читает SOAP-сообщения и строит деревья XML DOM.·
  • SoapSerializer - содержит методы создания SOAP-сообщения.·
  • IsoapTypeMapper, SoapTypeMapperFactory - интерфейсы, позволяющие работать со сложными типами данных.

С помощью объектов высокоуровневого API можно передавать данные только простых типов (int, string, float и т. п.), но спецификация SOAP 1.1 допускает работу с более сложными типами данных, например с массивами, структурами, списками и их комбинациями. Для работы с такими типами приходится использовать интерфейсы IsoapTypeMapper и SoapTypeMapperFactory.

Пример

Чтобы продемонстрировать работу SOAP, напишем несложный Web-сервис, который будет уметь складывать и вычитать числа. Для работы серверного приложения потребуется пакет IIS 5 в среде Windows 2000 или IIS4 на Windows NT 4.0 Service Pack 6, а также установленный SOAP Toolkit 2.0.

Требования клиентского приложения - ОС Microsoft Windows 98/Me или Windows NT 4.0 Service Pack 6/2000 Service Pack 1, а также установленный SOAP Toolkit 2.0.

Создание сервера

Откройте в VB новый проект ActiveX DLL. Измените название класса на SOAPClass, а имя проекта - на SOAPProj.

В классе создайте следующие методы:

В следующем окне Мастера можно выбрать методы, которые войдут в Web-сервис. В данном случае выберите все методы. Затем укажите, где будет находиться Web-приложение (например, http://wsd010/soap/), задайте тип приложения Listener (ASP или ISAPI), выберите ASP, формат схемы (по умолчанию). Укажите путь, где будут находиться файлы описания Web-сервиса, и кодировку. После окончания работы Мастера в Web-каталоге появятся файлы ASP, WSDL и WSML - это Listener для ASP и описания сервиса (см. листинги 1-3).

Осталось только настроить права доступа к Web-приложению - желательно установить NT Challenge/Response authentication. На этом работа по созданию сервера закончена.

Создание клиента

Откройте в VB новый проект Standard EXE. В меню Project/References сделайте ссылку на библиотеку Microsoft SOAP type library. Создайте на форме кнопку, в обработчике нажатия кнопки напишите следующий код:

Dim SoapClient As New SoapClient SoapClient.mssoapinit "http://wsd010/soap/SOAPService.wsdl" MsgBox SoapClient.AddNumbers(4, 3) MsgBox SoapClient.SubtractNumbers(3, 2)

Не забудьте изменить адрес Web-сервера и путь к WSDL-файлу во второй строке на адрес и путь к вашему Web-сервису.

После создания объекта SOAPClient его надо инициализировать - указать путь к документу описания Web-сервиса. После инициализации у объекта появятся методы Web-сервиса. С ними можно работать как с обычным COM-объектом.

С помощью замечательной утилиты MsSoapT.exe (Trace Utility), входящей в Toolkit, можно просматривать в режиме реального времени пакеты, идущие от клиента к серверу и обратно. Для этого надо в WSDL-файле найти тег и вместо строки типа http://wsd010/soap/SOAPService.ASP написать http://wsd010:8080/soap/SOAPService.ASP, то есть указать порт 8080. После этого нужно запустить утилиту трассирования и принять настройки по умолчанию, а затем создать новый объект Formatted Trace. Теперь все SOAP-пакеты работы с Web-сервисом доступны для оперативного просмотра. Если трассировщик не загружен, то в нужно убрать указание порта 8080. На рис. 4 приведено содержимое пакета запроса на выполнение метода SubstractNumbers.

А пакет ответа выглядит следующим образом:

1

Так выглядит пакет сервера, пришедший в ответ на запрос некорректного формата:

SOAP-ENV:Server Connector - Bad request to the server. -2146823238 800a13ba

Дополнительная информация по теме

http://msdn.microsoft.com/webservices/ и http://msdn.microsoft.com/soap/ - последние новости о SOAP и Web-сервисах от Microsoft. Там же можно найти свежие версии ПО.

http://www.vbxml.com/soap/ - много полезной информации для разработчиков. Есть презентации и учебники по SOAP.

http://www.w3.org/TR/SOAP/ - спецификация SOAP от W3C.

http://www.w3.org/TR/wsdl - сведения о стандарте Web Services Definition Language (WSDL) 1.1/

http://microsoft.public.xml.soap - в этой конференции специалисты помогут решить сложные проблемы программирования SOAP.

Листинг 1. Код Listener для ASP

<%@ LANGUAGE=VBScript %> <% Option Explicit On Error Resume Next Response.ContentType = "text/xml" Dim SoapServer If Not Application("SoapServerInitialized") Then Application.Lock If Not Application("SoapServerInitialized") Then Dim WSDLFilePath Dim WSMLFilePath WSDLFilePath = Server.MapPath("SOAPService.wsdl") WSMLFilePath = Server.MapPath("SOAPService.wsml") Set SoapServer = Server.CreateObject("MSSOAP.SoapServer") If Err Then SendFault "Cannot create SoapServer object. " & Err.Description SoapServer.Init WSDLFilePath, WSMLFilePath If Err Then SendFault "SoapServer.Init failed. " & Err.Description Set Application("SOAPServiceServer") = SoapServer Application("SoapServerInitialized") = True End If Application.UnLock End If Set SoapServer = Application("SOAPServiceServer") SoapServer.SoapInvoke Request, Response, "" If Err Then SendFault "SoapServer.SoapInvoke failed. " & Err.Description Sub SendFault(ByVal LogMessage) Dim Serializer On Error Resume Next " "URI Query" logging must be enabled for AppendToLog to work Response.AppendToLog " SOAP ERROR: " & LogMessage Set Serializer = Server.CreateObject("MSSOAP.SoapSerializer") If Err Then Response.AppendToLog "Could not create SoapSerializer object. " & Err.Description Response.Status = "500 Internal Server Error" Else Serializer.Init Response If Err Then Response.AppendToLog "SoapSerializer.Init failed. " & Err.Description Response.Status = "500 Internal Server Error" Else Serializer.startEnvelope Serializer.startBody Serializer.startFault "Server", "The request could not be processed due to a problem in the server. Please contact the system administrator. " & LogMessage Serializer.endFault Serializer.endBody Serializer.endEnvelope If Err Then Response.AppendToLog "SoapSerializer failed. " & Err.Description Response.Status = "500 Internal Server Error" End If End If End If Response.End End Sub %>

Листинг 2. Код файла WSDL

Листинг 3. Код файла WSDL

Лирическая часть.

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

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

Другие системы, обращаясь к этому серверу уже могут распоряжаться полученными от этого сервера данными по своему усмотрению - обрабатывать, накапливать, выдавать своим клиентам и т.д.

Ну вот, один из вариантов общения с такими серверами - это SOAP. SOAP протокол обмена xml-сообщениями.

Практическая часть.

Веб-сервис (так называется то, что предоставляет сервер и то, что используют клиенты) дает возможность общения с сервером четко структурированными сообщениями. Дело в том, что веб-сервис не принимает абы какие данные. На любое сообщение, которое не соответствует правилам, веб-сервис ответит ошибкой. Ошибка будет, кстати, тоже в виде xml с четкой структурой (чего нельзя сказать правда о тексте сообщения).

WSDL (Web Services Description Language). Правила, по которым составляются сообщения для веб-сервиса описываются так же с помощью xml и также имеют четкую структуру. Т.е. если веб-сервис предоставляет возможность вызова какого-то метода, он должен дать возможность клиентам узнать какие параметры для данного метода используются. Если веб-сервис ждет строку для метода Method1 в качестве параметра и строка должна иметь имя Param1, то в описании веб-сервиса эти правила будут указаны.

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

Для клиентов достаточно знать url веб-сервиса, wsdl всегда будет рядом, по которому можно получить представление о методах и их параметрах, которые предоставляет этот веб-сервис.

Какие плюсы у всех этих наворотов:

  • В большинстве систем описание методов и типов происходит в автоматическом режиме. Т.е. программисту на сервере достаточно сказать, что данный метод можно вызывать через веб-сервис, и wsdl-описание будет сгенерировано автоматом.
  • Описание, имеющее четкую структуру, читается любым soap-клиентом. Т.е. какой бы ни был веб-сервис, клиент поймет какие данные веб-сервис принимает. По этому описанию клиент может построить свою внутреннюю структуру классов объектов, т.н. binding"и. В итоге программисту, использующему веб-сервис, остается написать что-то типа (псевдокод):

    NewUser:=TSoapUser.Create("Вася","Пупкин","odmin"); soap.AddUser(NewUser);

  • Автоматическая валидация.

    • xml-валидация. xml должен быть well-formed. невалидный xml - сразу ошибка клиенту, пусть разбирается.
    • schema-валидация. xml должен иметь определенную структуру. xml не соответствует схеме - сразу ошибка клиенту, пусть разбирается.
    • проверка данных осуществляется soap-сервером, чтобы типы данных, ограничения соответствовали описанию.
  • Авторизация и аутентификация может быть реализована отдельным методом. нативно. либо, используя http-авторизацию.
  • Веб-сервисы могут работать как по soap-протоколу, так и по http, то есть через get-запросы. То есть, если в качестве параметров идут простые данные (без структуры), то можно вызвать просто обычный get www.site.com/users.asmx/GetUser?Name=Vasia или post. Впрочем это не везде и не всегда.
  • ... см. в википедии

Минусов тоже полно:

  • Неоправданно большой размер сообщений. Ну тут сама природа xml такова, что формат избыточный, чем больше тэгов, тем больше неполезной информации. Плюс soap добавляет своей избыточности. Для intranet-систем вопрос трафика стоит менее остро, чем для internet, поэтому soap для локальных сетей более востребован, в частности у Sharepoint есть soap веб-сервис, с которым с успехом (и некоторыми ограничениями) можно общаться.
  • Автоматическая смена описания веб-сервиса может сломать все клиенты. Ну это как бы для любой системы так, если не поддерживается обратная совместимость со старыми методами, все отвалится...
  • Не минус, но недостаток. Все действия по вызову методов должны быть атомарными. Например, работая с субд мы можем начать транзакцию, выполнить несколько запросов, потом откатиться или закоммитить. В soap транзакций нет. Один запрос-один ответ, разговор закончен.
  • Разбираться с описанием, что на стороне сервера (все ли правильно описано у меня?), что на клиенте (что мне тут наописывали?) бывает довольно сложно. Было несколько раз, когда мне приходилось разбираться с клиентской стороны, и убеждать серверного программера, что у него неверно описаны данные, а он в них вообще ничего понять не мог, ибо автоматическая генерация и он как бы и не должен, это дело софта. А ошибка естественно была в коде метода, программер ее не видел просто.
  • Практика показывает, что разработчики веб-сервисов страшно далеки от народа, использующего эти веб-сервисы. В ответ на какой-либо запрос (валидный со стороны) может прийти невразумительная ошибка "Ошибка 5. Все плохо". Все зависит от совести разработчиков:)
  • еще наверняка что-то не вспомнил...

В качестве примера есть открытый веб-сервис belavia:

  • http://86.57.245.235/TimeTable/Service.asmx - точка входа, там же текстовое описание методов для сторонних разработчиков.
  • http://86.57.245.235/TimeTable/Service.asmx?WSDL - wsdl описание методов и типов принимаемых и возращаемых данных.
  • http://86.57.245.235/TimeTable/Service.asmx?op=GetAirportsList - описание конкретного метода с примером вида xml-запроса и xml-ответа.

Можете вручную создать и послать запрос типа:

POST /TimeTable/Service.asmx HTTP/1.1 Host: 86.57.245.235 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://webservices.belavia.by/GetAirportsList" ru

в ответ придет:

HTTP/1.1 200 OK Date: Mon, 30 Sep 2013 00:06:44 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 Cache-Control: private, max-age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 2940

ЗЫ Раньше был открыт веб-сервис аэрофлота, но после того как 1C добавили поддержку soap в 8ку, куча 1с-бета-тестеров с успехом положили его. Сейчас что-то там поменяли (адреса не знаю, можно поискать, если интересно).
ЗЗЫ Дисклеймер. Рассказал на бытовом уровне. Пинать можно.