В каком году появились soap веб сервисы. Листинг класса PersonServiceImpl

В процессе эволюции Интернета появилась необходимость в создании распределенных приложений. Приложения, установленные на компьютере, обычно используют библиотеки, размещенные на нем. Одну библиотеку могут использовать несколько программ. Можно ли размещать аналоги библиотек в Интернете, чтобы разные сайты могли их вызывать? Оказывается, да.

Предприятия на своих страницах предоставляют разнообразную информацию. Например, со своего сайта http://www.Ford.com компания "Форд" публикует информацию о моделях и ценах. Дилер этой компании хотел бы иметь эту информацию и на своем сайте. Web-служба позволяет сайту-потребителю получать информацию с сайта-поставщика. Сайт -потребитель показывает эту информацию на своих страницах. Код для генерации этой информации написан один раз, но может использоваться многими потребителями. Данные представлены в простом текстовом виде, поэтому ими можно пользоваться независимо от платформы.

Web -сервисы широко используются и в Desktop, и в Интернет -приложениях. Они сами по себе являются не приложениями, а источниками данных для приложений. У них отсутствует пользовательский интерфейс . Web -сервисами необязательно пользоваться через сеть - они могут быть частью проекта, в котором используются.

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

Это дальнейшее развитие компонентного программирования CORBA и DCOM . Однако для использования таких компонентов необходимо регистрировать их в системе потребителя. Для web-служб это не требуется. Компоненты хорошо работают в локальных сетях. Протокол HTTP не приспособлен для вызова удаленных процедур ( RPC ). Даже в одной организации часто используются разные операционные системы, которые могут взаимодействовать только через HTTP .

Было предпринято несколько попыток создания языка коммуникации между разнородными системами - DCOM , CORBA , RMI , IIOP . Они не получили всеобщего распространения, так как каждый из них продвигался разными производителями и поэтому был привязан к технологиям конкретного изготовителя. Никто не хотел принимать чужой стандарт. Чтобы выйти из этой дилеммы, несколько компаний договорились выработать независимый от производителя стандарт обмена сообщениями через HTTP . В мае 2000 года компании IBM , Microsoft, HP, Lotus, SAP , UserLand и другие обратились к W3C и выдвинули SOAP в качестве кандидата на такой стандарт. SOAP произвел революцию в области разработки приложений, объединив два стандарта Интернета - HTTP и XML .

SOAP

Для взаимодействия с web -сервисами применяется протокол SOAP , основанный на XML . Можно было бы использовать просто XML , но это слишком свободный формат, в нем каждый документ фактически создает свой язык. SOAP - это соглашение о формате XML -документа, о наличии в нем определенных элементов и пространств имен.

SOAP позволяет публиковать и потреблять сложные структуры данных, например DataSet . В то же самое время его легко изучить. Текущая версия SOAP - 1.2.

SOAP - это Простой Протокол Обмена Данными (Simple Object Access Protocol ). SOAP создан для того, чтобы облегчать взаимодействие приложениям через HTTP . Это особый независимый от платформы формат обмена сообщениями через Интернет . Сообщение SOAP - это обычный XML -документ. Стандарт

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

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

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

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

Ну вот, один из вариантов общения с такими серверами - это 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с-бета-тестеров с успехом положили его. Сейчас что-то там поменяли (адреса не знаю, можно поискать, если интересно).
ЗЗЫ Дисклеймер. Рассказал на бытовом уровне. Пинать можно.

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с", то пишите комментарии, и мы все обсудим.

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

Введение

Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется 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.

Алексей Бойко

SOAP и веб-сервисы XML на платформе.Net

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

платформ и языков, который ранее был просто недоступен.

Эндрю Троелсен (обладатель титула MVP (Most Valuable Professional in Microsoft))

Если вы еще не работали с веб-сервисами XML, то наверняка слышали слово «SOAP». Настало время разобраться с этими понятиями.

Intro

Если вас интересует Интернет или сети поменьше, скорее всего рано или поздно вы столкнетесь с веб-сервисами XML. Веб-сервис XML – это не только веб-приложение, способное выводить информацию в браузер. Скорее это технология удаленного взаимодействия, позволяющая вызывать методы и свойства объекта в сети с помощью стандартных HTTP-запросов.

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

В качестве информационного «транспорта» между сервисом и клиентом можно использовать HTTP-методы GET или POST.

А можно «наложить» поверх еще один протокол – SOAP (Simple Object Access Protocol). Обычно так и поступают, так как в этом случае возможна передача сложных типов (включая пользовательские). А классические методы GET и POST поддерживают только перечни, простые массивы и строки.

Пример SOAP-взаимодействия

SOAP-сообщение – это XML-документ, помещенный в тело HTTP-запроса.

Листинг 1. Структура SOAP-сообщения

Взаимодействие клиента и сервиса происходит следующим образом:

  • клиент формирует SOAP-запрос и отправляет его сервису;
  • сервис на удаленном компьютере выполняет процедуру и отправляет SOAP-ответ.

Например, вот так может выглядеть SOAP-запрос, вызывающий метод HelloWorld() удаленного веб-сервиса XML:

Листинг 2. Пример SOAP-запроса

Метод HelloWorld(), как и полагается, возвращает строку «Здравствуй, мир!»:

Листинг 3. Пример SOAP-ответа

Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Здравствуй, мир!

Создание веб-сервиса XML на платформе.NET 2.0

Создать сервис можно различными способами, мы будем использовать Visual Studio 2005. Нажмите «File -> New -> Web Site», в раскрывшемся окне выберите «ASP.NET web Service». По указанному при создании адресу вы обнаружите следующие файлы и директории (см. рис. 1).

В принципе, сервис может содержать только один-единственный файл с расширением *.asmx. (Для обозначения веб-сервисов.Net используется расширение *.asmx.) В данном случае это не так, посмотрите содержимое файла Service.asmx:

Листинг 4. В Service.asmx определен внешний файл поддержки

<%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" class="Service" %>

Атрибут CodeBehind указывает внешний файл, расположенный в папке App_Code, в котором размещен программный код, реализующий метод HelloWorld():

Листинг 5. Файл Service.cs, реализующий метод HelloWorld()

using System;

using System.Web;

using System.Web.Services;

Public Service () {

Return "Hello World";

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

Листинг 6. Service.asmx без внешнего кода поддержки

<%@ WebService Language="C#" class="Service" %>

using System;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

public class Service: System.Web.Services.WebService

Public Service () {

Public string HelloWorld() {

Return "Hello World";

Нам это ни к чему, и так поступать мы не станем.

Как видите, единственный метод нашего веб-сервиса помечен атрибутом , информирующим среду выполнения ASP.NET о том, что этот метод доступен для поступающих HTTP-запросов. Не обозначенные таким атрибутом члены не будут доступны клиентским программам.

Для наших экспериментов вполне подходит такой простой сервис, осталось только опубликовать его.

Публикация веб-сервиса XML с помощью IIS

Речь пойдет не о публикации в Интернете, а о создании условий для тестирования нашего сервиса на локальном компьютере.

Первым делом установите IIS (Internet Information Server). Для этого откройте окно «Установка и удаление программ» и выберите в нем «Установка компонентов Windows». (Некоторые версии Windows не предполагают установку IIS, например Windows XP Home Edition.)

Примечание: сервер IIS лучше устанавливать раньше, чем.Net Framework, иначе придется настроить IIS на поддержку.Net-приложений с помощью запуска утилиты командной строки aspnet_regiis.exe (с флагом /i).

Создайте виртуальный каталог. Если вы используете Windows XP Pro, войдите в «Панель управления -> Администрирование -> Internet Information Services». В раскрывшемся окне выберите «Действие -> Создать -> Виртуальный каталог».

Будет запущен мастер создания виртуальных каталогов. Укажите в качестве псевдонима Soap1 и задайте путь к каталогу, в котором хотите разместить сервис, например C:\Soap1. Теперь скопируйте туда содержимое нашего веб-сервиса.

Наберите в адресной строке браузера http://localhost/soap1/Service.asmx, и вы должны увидеть страницу тестирования сервиса (см. рис. 2).

Просмотр SOAP-сообщений

Страница тестирования не позволяет отправлять и читать SOAP-сообщения. По этой причине придется воспользоваться сторонними разработками, я рекомендую использовать soapUI. (Это бесплатный продукт, доступный по адресу http://www.soapui.org .)

После установки soapUI создайте новый проект под наз-ванием soap1, оставив поле Initial WSDL пустым (см. рис. 3).

Правой кнопкой мышки щелкните на только что созданном проекте и выберите «Add WSDL from URL». В открывшемся диалоговом окне введите http://localhost/soap1/Service.asmx?wsdl. Теперь у нас есть возможность отправлять SOAP-запросы к нашему сервису и просматривать полученные ответы. (Запросы будут сгенерированы soapUI автоматически.)

Что же такое этот WSDL? Документ WSDL описывает возможности взаимодействия клиентов с веб-сервисом. Там описывается, какие методы сервиса доступны для внешнего вызова, какие параметры они принимают и что возвращают, а также прочая информация, необходимая для удаленного взаимодействия. Такой документ можно составить вручную, а можно доверить его генерацию серверу, для этого достаточно приписать суффикс?wsdl к URL, указывающему на файл *.asmx.

Чтобы посмотреть WSDL-документ нашего сервиса, введите в браузере http://localhost/soap1/Service.asmx?wsdl. Информацию именно из этого документа использует soapUI для автоматической генерации SOAP-запросов.

SOAP Extensions

Как вы, наверное, заметили для создания веб-сервиса XML (как и клиента) не обязательно заботиться о виде SOAP-сообщений. Достаточно пометить нужные методы атрибутом , и среда выполнения ASP.NET сама составит пакеты нужного формата.

На рис. 4 показаны запрос и ответ веб-сервиса, полученные с помощью программы soapUI.

Повторим еще раз. Запрос сгенерирован soapUI – при создании реальных клиентов для сервиса тоже не требуется вручную форматировать SOAP-пакеты. В создании ответа сервиса мы также не принимали непосредственного участия. Все это происходит автоматически.

Однако вполне вероятно, что вам потребуется самостоятельно модифицировать эти пакеты. Например, произвести сжатие или шифрование передаваемых данных. В этом и есть назначение SOAP Extensions.

SOAP Extensions – это механизм, позволяющий произвольным образом изменять принимаемые и отправляемые SOAP-сообщения.

«Путь» SOAP-сообщения

Чтобы приступить к программированию, нужно рассмотреть путь, который проходит SOAP-сообщение, прежде чем оно будет получено и обработано соответствующим методом (см. рис. 5).

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

Входящие пакеты проходят десериализацию (восстановление объекта из XML-описания), а отправляемые сериализацию (создание XML-описания объекта).

На рис. 5 показаны четыре точки (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize), в которых мы, с помощью SOAP Extensions, можем перехватить SOAP-сообщение. Модифицировать его и отправить дальше.

Реализация SOAP Extension

Для начала определимся с заданием: пусть мы хотим изменить отправляемые веб-сервисом SOAP-пакеты как показано в листинге 7:

Листинг 7. «Старый» и новый ответы web-сервиса XML

Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Hello World

Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Зашифрованный текст

План действий для реализации SOAP Extension:

  • Создаем dll с классом, наследуемым от SoapExtension.
  • Добавляем к нашему веб-сервису папку bin и кладем туда созданную dll.
  • Добавляем к сервису файл web.config и вносим в него нужные изменения.

Роль папки bin и файла web.config рассмотрим позже.

Создание DLL c SOAP Extension

Создайте новый проект «Class Library» под названием SoapExtensionLib. В этом проекте потребуется реализовать только один класс, который будет выполнять необходимые нам модификации SOAP-пакетов. Этот класс должен быть наследованным от класса SoapExtension.

Листинг 8. Создание класса, наследуемого от SoapExtension

using System;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.IO;

using System.Net;

using System.Xml;

Каждое SOAP Extension получает как параметр поток, содержащий передаваемый по сети объект (до или после сериализации). И обязано возвращать поток.

SOAP Extension можно представить как «врезку», которую можно поставить в одной или всех четырех точках (BeforeSerialize, AfterDeserialize, BeforeDeserialize, AfterSerialize), показанных на рис. 5. В каждой точке таких «врезок» может быть сколько угодно (см. рис. 6).

Для получения этих потоков используется метод ChainStream.

Листинг 9. Реализация метода ChainStream

public class TraceExtension: SoapExtension

Stream wireStream;

Stream appStream;

// метод в качестве входного параметра

// получает поток, содержащий передаваемый объект

Public override Stream ChainStream(Stream stream)

WireStream = stream;

AppStream = new MemoryStream();

Return appStream;

В точке BeforeDeserialize поток wireStream содержит принятый из сети SOAP-запрос. Этот SOAP-запрос нужно передать потоку приложения (потоку appStream).

А в точке AfterSerialize необходимо передать потоку wireStream отправляемый в сеть SOAP-ответ, который будет размещаться в appStream.

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

Листинг 10. Реализация метода ProcessMessage, не модифицирующего SOAP-сообщения

// ProcessMessage, выполняющий обязательное копирование

// потоков в двух точках (BeforeDeserialize и AfterSerialize)

Switch (message.Stage)

// в точке BeforeDeserialize необходимо передать

// SOAP-запрос из потока сети (wireStream)

// в поток приложения (appStream)

Case SoapMessageStage.BeforeDeserialize:

Copy(wireStream, appStream);

AppStream.Position = 0;

Break;

// в точке AfterSerialize необходимо передать

// SOAP-ответ из потока приложения в поток сети

AppStream.Position = 0;

Break;

void Copy(Stream from, Stream to)

TextReader reader = new StreamReader(from);

TextWriter writer = new StreamWriter(to);

Writer.WriteLine(reader.ReadToEnd());

Writer.Flush();

Листинг 10 можно воспринимать как болванку для дальнейших экспериментов. В такой реализации метода ProcessMessage нет никакого смысла – исходящий SOAP-ответ никак не модифицируется. Исправим это:

Листинг 11. Реализация метода ProcessMessage, модифицирующего SOAP-ответ

public override void ProcessMessage(SoapMessage message)

Switch (message.Stage)

Case SoapMessageStage.AfterSerialize:

WriteOutput(message);

Break;

// часть кода вырезана для экономии места

// перепишем SOAP-ответ

public void WriteOutput(SoapMessage message)

AppStream.Position = 0;

// создадим XML документ из потока

XmlDocument document = new XmlDocument();

Document.Load(appStream);

// Для использования XPath нужно определить

// NamespaceManager

XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);

Nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

XmlNode ResultNode = document.SelectSingleNode("//soap:Body", nsmgr);

// заменем содержимое узла

ResultNode.InnerText = "зашифрованный текст";

// очистим поток и запишем в него новый SOAP-ответ

AppStream.SetLength(0);

AppStream.Position = 0;

Document.Save(appStream);

// ОБЯЗАТЕЛЬНОЕ ДЕЙСТВИЕ

// передадим SOAP-ответ из потока приложения (appStream)

// в поток сети (wireStream)

AppStream.Position = 0;

Copy(appStream, wireStream);

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

Листинг 12. Другие обязательно реализуемые методы

// В соотвествии с правилами наследования мы обязаны

// определить эти методы, однако мы их никак не используем

public override object ?

GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)

Return null;

public override object GetInitializer(Type WebServiceType)

Return null;

public override void Initialize(object initializer)

Return;

Всё, компилируем проект. Наконец-то мы получили dll с SOAP Extension. Полный листинг SoapExtensionLib.dll находится на сайте журнала в разделе «Исходный код».

Настройка веб-сервиса для работы с SOAP Extension

Опять откройте проект нашего веб-сервиса XML с помощью Visual Studio. Нажмите «WebSite -> Add Reference» и выберите созданный ранее SoapExtensionLib.dll.

К проекту автоматически будет добавлена папка Bin. На файлы *.dll, расположенные в папке Bin, приложение ссылается автоматически.

Теперь положите в директорию веб-сервиса файл Web.Config следующего содержания:

Листинг 13. Файл Web.Config

Priority="1"

Group="0" />

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

С помощью файла Web.Config мы информируем среду ASP.NET о том, что мы добавили к веб-сервису XML Soap Extension, реализованное в классе TraceExtension который расположен в файле SoapExtensionLi.dll.

Листинг 14. Секция webServices в файле Web.Config

Priority="1"

Group="0" />

Как вы уже знаете, можно сделать множество SOAP Extension, и поток, несущий в себе передаваемый объект (до или после сериализации), будет проходить через каждое из них. Порядок прохождения потоком различных SOAP Extension задается с помощью атрибутов priority и group.

Стоит отметить, что сконфигурировав данным способом Web.Config, мы информируем среду о том, что наше SOAP Extension будет вызываться для каждого метода сервиса, помеченного атрибутом . Существует возможность создать свой атрибут и помечать им только те методы, для которых нужно вызвать SOAP Extension.

Листинг 15. Пример использования собственного атрибута

public string HelloWorld() {

Return "Hello World";

Для этого требуется добавить в SoapExtensionLi.dll класс, наследованный от SoapExtensionAttribute (см. рис. 8).

Заключение

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


Вконтакте