В процессе эволюции Интернета появилась необходимость в создании распределенных приложений. Приложения, установленные на компьютере, обычно используют библиотеки, размещенные на нем. Одну библиотеку могут использовать несколько программ. Можно ли размещать аналоги библиотек в Интернете, чтобы разные сайты могли их вызывать? Оказывается, да.
Предприятия на своих страницах предоставляют разнообразную информацию. Например, со своего сайта 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-описание будет сгенерировано автоматом.
Автоматическая валидация.
- xml-валидация. xml должен быть well-formed. невалидный xml - сразу ошибка клиенту, пусть разбирается.
- schema-валидация. xml должен иметь определенную структуру. xml не соответствует схеме - сразу ошибка клиенту, пусть разбирается.
- проверка данных осуществляется soap-сервером, чтобы типы данных, ограничения соответствовали описанию.
- Авторизация и аутентификация может быть реализована отдельным методом. нативно. либо, используя http-авторизацию.
- Веб-сервисы могут работать как по soap-протоколу, так и по http, то есть через get-запросы. То есть, если в качестве параметров идут простые данные (без структуры), то можно вызвать просто обычный get www.site.com/users.asmx/GetUser?Name=Vasia или post. Впрочем это не везде и не всегда.
- ... см. в википедии
Описание, имеющее четкую структуру, читается любым soap-клиентом. Т.е. какой бы ни был веб-сервис, клиент поймет какие данные веб-сервис принимает. По этому описанию клиент может построить свою внутреннюю структуру классов объектов, т.н. binding"и. В итоге программисту, использующему веб-сервис, остается написать что-то типа (псевдокод):
NewUser:=TSoapUser.Create("Вася","Пупкин","odmin"); soap.AddUser(NewUser);
Минусов тоже полно:
- Неоправданно большой размер сообщений. Ну тут сама природа 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"
в ответ придет:
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
Теперь опишем его программно
// Создаем объект и наполняем его данными СвояФабрика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 = "В этом варианте нам придется собрать 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
5. Если аутентификация предполагает использование Cookie, то нашлась следующая
P.S. Если у вас появились вопросы, предложения по улучшению кода, есть собственные рецепты, отличные от описанных, вы нашли ошибки или считаете, что автор "ниправ" и ему "не место в 1с", то пишите комментарии, и мы все обсудим.
Заголовок топика – это действительно вопрос, т.к. я сам не знаю, что это и впервые попробую поработать с этим в рамках настоящей статьи. Единственное, что могу гарантировать, что код, представленный ниже, будет работать, однако мои фразы будут лишь предположениями и догадками о том, как я сам все это понимаю. Итак, поехали…
Введение
Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется RPC (Remote Procedure Calling – удаленный вызов процедур). В качестве примеров можно привести технологии CORBA, а для Java – RMI (Remote Method Invoking – удаленный вызов методов). И все вроде в них хорошо, особенно в CORBA, т.к. с ней можно работать на любом языке программирования, но чего-то все же не хватало. Полагаю, что минусом CORBA является то, что она работает через какие-то свои сетевые протоколы вместо простого HTTP, который пролезет через любой firewall. Идея веб-сервиса заключалась в создании такого RPC, который будет засовываться в HTTP пакеты. Так началась разработка стандарта. Какие у этого стандарта базовые понятия:- SOAP . Прежде чем вызвать удаленную процедуру, нужно этот вызов описать в XML файле формата SOAP. SOAP – это просто одна из многочисленных XML разметок, которая используется в веб-сервисах. Все, что мы хотим куда-то отправить через HTTP, сначала превращается в XML описание SOAP, потом засовывается в HTTP пакет и посылается на другой компьютер в сети по TCP/IP.
- WSDL . Есть веб-сервис, т.е. программа, методы которой можно удаленно вызывать. Но стандарт требует, чтобы к этой программе прилагалось описание, в котором сказано, что «да, вы не ошиблись – это действительно веб-сервис и можно у него вызвать такие-то такие-то методы». Такое описание представляется еще одним файлом XML, который имеет другой формат, а именно WSDL. Т.е. WSDL – это просто XML файл описания веб-сервиса и больше ничего.
Общий подход
В веб-сервисах всегда есть клиент и сервер. Сервер – это и есть наш веб-сервис и иногда его называют endpoint (типа как, конечная точка, куда доходят SOAP сообщения от клиента). Нам нужно сделать следующее:- Описать интерфейс нашего веб-сервиса
- Реализовать этот интерфейс
- Запустить наш веб-сервис
- Написать клиента и удаленно вызвать нужный метод веб-сервиса
Сервер
Запустим 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">
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. Я надеюсь, что изложенного материала будет вполне достаточно, чтобы при необходимости вы смогли заняться более глубоким изучением темы. Вконтакте