- WSDL – Пример
- SOAP – Стандарты
- WSDL – элемент
- 4 Пишем свой WSDL
- Указывает на заметку
- 1 Постановка задачи
- 2 Какими данными будем меняться?
- SOAP через HTTP
- 6 SOAP-клиент на подходе
- Пример ошибки SOAP
- Структура сообщения SOAP
- WSDL – Элементы
- WSDL – элемент
- Well Formed XML
- Есть корневой элемент
- У каждого элемента есть закрывающийся тег
- Теги регистрозависимы
- Правильная вложенность элементов
- Атрибуты оформлены в кавычках
- 2-совместимое сообщение SOAP
- WSDL – элемент
- SOAP – Примеры
- SOAP – структура сообщения
- Атрибуты заголовка SOAP
- 5 Наш первый SOAP-сервер
- Коды ошибок SOAP
WSDL – Пример
Ниже приведен файл WSDL, предоставленный для демонстрации простой программы WSDL.
Предположим, что сервис предоставляет единственную общедоступную функцию, называемую sayHello . Эта функция ожидает один строковый параметр и возвращает приветствие одной строки. Например, если вы передаете параметр world, то сервисная функция sayHello возвращает приветствие «Hello, world!».
SOAP – Стандарты
В июле 2001 года рабочая группа по протоколу XML выпустила «рабочий проект» SOAP 1.2. В рамках W3C этот документ официально находится в стадии разработки, что означает, что документ, вероятно, будет обновляться много раз, прежде чем будет завершен.
SOAP версии 1.1 доступен в Интернете по адресу http://www.w3.org/TR/SOAP/.
Рабочий проект SOAP версии 1.2 доступен по адресу http://www.w3.org/TR/soap12/.
Обратите внимание, что W3C также содержит представление для «SOAP-сообщений с вложениями», которое отделено от основной спецификации SOAP. Эта спецификация позволяет сообщениям SOAP включать двоичные вложения, такие как изображения и звуковые файлы. Для получения полной информации см. Примечание W3C по адресу http://www.w3.org/TR/SOAP-attachments .
WSDL – элемент
Элемент types описывает все типы данных, используемые между клиентом и сервером.
WSDL не привязан исключительно к конкретной системе ввода.
WSDL использует спецификацию XML-схемы W3C в качестве выбора по умолчанию для определения типов данных.
Если служба использует только простые встроенные типы XML-схемы, такие как строки и целые числа, то элемент types не требуется.
WSDL позволяет определять типы в отдельных элементах, чтобы их можно было повторно использовать в нескольких веб-службах.
Вот фрагмент кода, взятый из спецификации W3C. Этот код показывает, как элемент типов может использоваться в WSDL.
Типы данных решают проблему определения типов данных и форматов, которые вы собираетесь использовать с вашими веб-сервисами. Информация о типе распределяется между отправителем и получателем. Таким образом, получатели сообщений должны иметь доступ к информации, которую вы использовали для кодирования ваших данных, и должны понимать, как их декодировать.
4 Пишем свой WSDL
Вы помните о том, что WSDL и есть наш веб-сервис? Надеюсь, что помните! Как мы его напишем, так на нем наш маленький веб-сервис и поплывет. Поэтому, предлагаю не халтурить.
Вообще, для того, чтобы у нас все работало правильно нам надо передавать клиенту WSDL-файл с правильным MIME-типом. Для этого необходимо настроить ваш веб-сервер соответствующим образом, а именно – установить для файлов с расширением «*.wsdl» MIME-тип равный следующей строке:
Но на практике, я обычно отправлял посредством PHP HTTP-заголовок«text/xml»:
header(«Content-Type: text/xml; charset=utf-8»);
и все прекрасно работало!
Хочу сразу предупредить, наш простенький веб-сервис будет иметь довольно внушительное описание, поэтому не пугайтесь, т.к. большая часть текста является обязательной водой и написав ее один раз можно постоянно копировать от одного веб-сервиса к другому!
Поскольку WSDL – это XML, то в самой первой строке необходимо прямо об этом и написать. Корневой элемент файла всегда должен называться «definitions»:
Обычно, WSDL состоит из 4-5 основных блоков. Самый первый блок – определение веб-сервиса или другими словами – точки входа.
Здесь написано, что у нас есть сервис, который называется – «SmsService». В принципе, все имена в WSDL-файле могут быть вами изменены на какие только пожелаете, т.к. они не играют абсолютно никакой роли.
После этого мы объявляем о том, что в нашем веб-сервисе «SmsService» есть точка входа («port»), которая называется «SmsServicePort». Именно в эту точку входа и будут отправляться все запросы от клиентов к серверу. И указываем в элементе «address» ссылку на файл-обработчик, который будет принимать запросы.
После того, как мы определили веб-сервис и указали для него точку входа – необходимо привязать к нему поддерживаемые процедуры:
Для этого перечисляется какие операции и в каком виде у будут вызываться. Т.е. для порта «SmsServicePort» определена привязка под именем «SmsServiceBinding», которая имеет тип вызова «rpc» и в качестве протокола передачи (транспорта) используется HTTP. Т.о., мы здесь указали, что будем осуществлять RPC вызов поверх HTTP. После этого мы описываем какие процедуры (operation) поддерживаются в веб-сервисе. Мы будем поддерживать всего одну процедуру – «sendSms». Через эту процедуру будут отправляться на сервер наши замечательные сообщения! После того, как была объявлена процедура, необходимо указать в каком виде будут передаваться данные. В данном случае указано, что будут использоваться стандартные SOAP-конверты.
После этого нам необходимо привязать процедуру к сообщениям:
Для этого мы указываем, что наша привязка («binding») имеет тип «SmsServicePortType» и в элементе «portType» с одноименным типу именем указываем привязку процедур к сообщениям. И так, входящее сообщение (от клиента к серверу) будет называться «sendSmsRequest», а исходящее (от сервера к клиенту) «sendSmsResponse». Как и все имена в WSDL, имена входящих и исходящих сообщения – произвольные.
Теперь нам необходимо описать сами сообщения, т.е. входящие и исходящие:
Для этого мы добавляем элементы «message» с именами «sendSmsRequest» и «sendSmsResponse» соответственно. В них мы указываем, что на вход должен прийти конверт, структура которого соответствует типу данных «Request». После чего с сервера возвращается конверт содержащий тип данных – «Response».
Теперь надо сделать самую малость – добавить описание данных типов в наш WSDL-файл! И как вы думаете, как описываются в WSDL входящие и исходящие данные? Думаю, что вы уже все давно поняли и сказали сами себе, что при помощи XML-схем! И вы будете абсолютно правы!
Можно нас поздравить! Наш первый WSDL был написан! И мы еще на один шаг приблизились к достижению поставленной цели.
Далее мы разберемся с тем, что нам предоставляет PHP для разработки собственных распределенных приложений.
Указывает на заметку
SOAP – это протокол связи, предназначенный для связи через Интернет.
SOAP может расширить HTTP для обмена сообщениями XML.
SOAP обеспечивает транспорт данных для веб-сервисов.
SOAP может обмениваться полными документами или вызывать удаленную процедуру.
SOAP может использоваться для трансляции сообщения.
SOAP не зависит от платформы и языка.
SOAP – это способ определения, какая информация отправляется и каким образом.
SOAP позволяет клиентским приложениям легко подключаться к удаленным службам и вызывать удаленные методы.
Хотя SOAP может использоваться в различных системах обмена сообщениями и может доставляться через различные транспортные протоколы, первоначальная цель SOAP – удаленные вызовы процедур, транспортируемые через HTTP.
Другие платформы, в том числе CORBA, DCOM и Java RMI, предоставляют функциональность, аналогичную SOAP, но сообщения SOAP написаны полностью на XML и поэтому уникально независимы от платформы и языка.
1 Постановка задачи
В начале предлагаю разобраться с тем результатом, которого мы достигнем в конце топика. Как было объявлено выше, мы будем писать сервис по отправке sms-сообщений, а если еще точнее, то к нам будут поступать сообщения из разных источников по протоколу SOAP. После чего, мы рассматрим в каком виде они приходят на сервер. Сам процесс постановки сообщений в очередь для их дальнейшей отправки провайдеру, к сожалению, выходит за рамки данного поста по многим причинам.

2 Какими данными будем меняться?
Отлично, с границами мы определились! Следующий шаг, который необходимо сделать – решить какими данными мы будем обмениваться между сервером и клиентом. На эту тему предлагаю долго не мудрить и сразу для себя ответить на главные вопросы:
Что-то мне подсказывает, что для этого необходимо посылать следующее:
В принципе, двух этих характеристик достаточно для отправки, но мне сразу представляется случай, как sms-ка с поздравлением о дне рождения приходит вам в 3 часа утра, или 4! В этот момент я буду всем очень благодарен за то, что про меня не забыли! Поэтому, мы также будем посылать на сервер и
Следующее, что я бы хотел отправлять на сервер, так это
Данный параметр не является обязательным, но он может нам очень сильно пригодиться в случае, если быстро понадобится сказать боссу о том, скольких из наших клиентов мы «обрадовали» своим известием, а также нарисовать какую-нибудь красивую статистику на этот счет.
И все же, я что-то забыл! Если еще немного порефлексировать, то стоит отметить, что клиент за раз может отправить на сервер как одно sms-сообщение, так и некоторое их количество. Другими словами, в одном пакете данных может быть от одного до бесконечности сообщений.
В результате мы получаем, что для отправки sms-сообщения нам необходимы следующие данные:

На первый вопрос мы ответили, теперь необходимо ответить на второй вопрос. И пожалуй, я позволю себе немного с халтурить. Поэтому, с сервера мы будем присылать только булевы данные, значение которых имеет следующий смысл:
На этом мы закончили описание постановки задачи! И наконец-то приступим к самому интересному – будем разбираться что за диковинный зверь этот SOAP!
SOAP через HTTP
Логично, что SOAP-запросы отправляются через HTTP-запрос, а SOAP-ответы возвращаются в содержимом HTTP-ответа. Хотя запросы SOAP можно отправлять через HTTP GET, в спецификации содержатся сведения только о HTTP POST.
Кроме того, как HTTP-запросы, так и ответы требуются для установки типа контента text / xml.
Спецификация SOAP требует, чтобы клиент предоставил заголовок SOAPAction, но фактическое значение заголовка SOAPAction зависит от реализации сервера SOAP.
Например, чтобы получить доступ к службе перевода AltaVista BabelFish, размещенной в XMethods, в качестве заголовка SOAPAction необходимо указать следующее.
Даже если серверу не требуется полный заголовок SOAPAction, клиент должен указать пустую строку (“”) или нулевое значение.
Вот пример запроса, отправленного через HTTP в службу перевода XMethods Babelfish:
Обратите внимание на тип содержимого и заголовок SOAPAction. Также обратите внимание, что метод BabelFish требует двух параметров String. Режим перевода en_fr переводит с английского на французский.
Вот ответ от XMethods –
Ответы SOAP, доставляемые через HTTP, должны следовать тем же кодам состояния HTTP. Например, код состояния 200 OK указывает на успешный ответ. Код состояния 500 Internal Server Error указывает, что произошла ошибка сервера и что ответ SOAP содержит элемент Fault.
6 SOAP-клиент на подходе
Прежде всего нам надо создать файл, в котором будем писать клиент. Как обычно, мы его создадим в корне хоста и назовем «client.php», а внутри напишем следующее:
Опишем наши объекты. Когда мы писали WSDL в нем для входящего на сервер конверта описывались три сущности: Request, MessageList и Message. Соответственно классы Request, MessageList и Message являются отражениями этих сущностей в нашем PHP-скрипте.
После того, как мы определили объекты, нам необходимо создать объект ($req), который будем отправлять на сервер. После чего идут две самые заветные для нас строки! Наш SOAP-клиент! Верите или нет, но этого достаточно для того, чтобы на наш сервер начали сыпаться сообщения от клиента, а также для того, чтобы наш сервер успешно их принимал и обрабатывал! В первой из них мы создаем экземпляр класса SoapClient и передаем в его конструктор адрес расположения WSDL-файла, а в параметрах явно указываем, что работать мы будем по протоколу SOAP версии 1.2. В следующей строке мы вызываем метод sendSms объекта $client и сразу же выводим в браузере результат.
Давайте запусти и посмотрим что-же у нас наконец-то получилось!
Мне с сервера вернулся следующий объект:
И это замечательно, т.к. теперь мы точно знаем о том, что наш сервер работает и не просто работает, но еще и может возвращать на клиент какие-то значения!
Теперь посмотрим на лог, который мы предусмотрительно ведем на серверной стороне! В первой его части мы видим необработанные данные, которые поступили на сервер:
Это и есть конверт. Теперь вы знаете как он выглядит! Но постоянно на него любоваться нам вряд ли будет интересно, поэтому давайте десереализуем объект из лог-файла и посмотрим все ли у нас хорошо:
Как видим, объект десериализовался правильно, с чем я нас всех хочу поздравить! Далее нас ждет что-то более интересно! А именно – мы будем отправлять клиентом на сервер не одно sms-сообщение, а целую пачку (если быть точнее, то целых три)!
Пример ошибки SOAP
Следующий код является примером неисправности. Клиент запросил метод с именем ValidateCreditCard , но служба не поддерживает такой метод. Это представляет ошибку запроса клиента, и сервер возвращает следующий ответ SOAP –
Структура сообщения SOAP
Следующий блок отображает общую структуру сообщения SOAP –
WSDL – Элементы
WSDL разбивает веб-службы на три определенных идентифицируемых элемента, которые могут быть объединены или использованы повторно после определения.
Три основных элемента WSDL, которые могут быть определены отдельно:
Документ WSDL имеет различные элементы, но они содержатся в этих трех основных элементах, которые можно разрабатывать как отдельные документы, а затем их можно объединять или повторно использовать для формирования полных файлов WSDL.
WSDL – элемент
Привязки могут быть доступны через несколько транспортов, включая HTTP GET, HTTP POST или SOAP.
Привязки предоставляют конкретную информацию о том, какой протокол используется для передачи операций portType .
Привязки предоставляют информацию о том, где находится сервис.
Вы можете указать несколько привязок для одного portType .
Элемент привязки имеет два атрибута: атрибут name и type .
Атрибут name определяет имя привязки, а атрибут type указывает на порт для привязки, в данном случае это порт «tns: Hello_PortType».
Well Formed XML
Разработчик сам решает, какой XML будет считаться правильным, а какой нет. Но есть общие правила, которые нельзя нарушать. X ML должен быть well formed, то есть синтаксически корректный.
Чтобы проверить XML на синтаксис, можно использовать любой XML Validator (так и гуглите). Я рекомендую сайт w3schools. Там есть сам валидатор + описание типичных ошибок с примерами.
В готовый валидатор вы просто вставляете свой XML (например, запрос для сервера) и смотрите, всё ли с ним хорошо. Но можете проверить его и сами. Пройдитесь по правилам синтаксиса и посмотрите, следует ли им ваш запрос.
Правила well formed XML:

Давайте пройдемся по каждому правилу и обсудим, как нам применять их в тестировании. То есть как правильно «ломать» запрос, проверяя его на well-formed xml. Зачем это нужно? Посмотреть на фидбек от системы. Сможете ли вы по тексту ошибки понять, где именно облажались?
См также:
Сообщения об ошибках — тоже документация, тестируйте их! — зачем тестировать сообщения об ошибках
Есть корневой элемент
Нельзя просто положить рядышком 2 XML и полагать, что «система сама разберется, что это два запроса, а не один». Не разберется. Потому что не должна.
И если у вас будет лежать несколько тегов подряд без общего родителя — это плохой xml, не well formed. Всегда должен быть корневой элемент:
Что мы делаем для тестирования этого условия? Правильно, удаляем из нашего запроса корневые теги!
У каждого элемента есть закрывающийся тег
Тут все просто — если тег где-то открылся, он должен где-то закрыться. Хотите сломать? Удалите закрывающийся тег любого элемента.
Но тут стоит заметить, что тег может быть один. Если элемент пустой, мы можем обойтись одним тегом, закрыв его в конце:
Это тоже самое, что передать в нем пустое значение

Итого — если есть открывающийся тег, должен быть закрывающийся. Либо это будет один тег со слешом в конце.
Для тестирования удаляем в запросе любой закрывающийся тег.
Теги регистрозависимы
Как написали открывающий — также пишем и закрывающий. Т ОЧНО ТАК ЖЕ! А не так, как захотелось.
А вот для тестирования меняем регистр одной из частей. Такой XML будет невалидным
Правильная вложенность элементов
Элементы могут идти друг за другом

Один элемент может быть вложен в другой

Но накладываться друг на друга элементы НЕ могут!

Атрибуты оформлены в кавычках
Даже если вы считаете атрибут числом, он будет в кавычках:
Для тестирования пробуем передать его без кавычек:
2-совместимое сообщение SOAP
Ниже приведен пример сообщения SOAP, совместимого с v1.2.
WSDL – элемент
Вот фрагмент кода из последней главы, в котором используется элемент определения .
Из приведенного выше примера можно сделать вывод, что определения –
является контейнером всех других элементов.
указывает, что этот документ называется HelloService .
указывает атрибут targetNamespace . TargetNamespace – это соглашение XML-схемы, которое позволяет документу WSDL ссылаться на себя. В этом примере мы указали targetNamespace http://www.examples.com/wsdl/HelloService.wsdl
определяет пространство имен по умолчанию: xmlns = http: //schemas.xmlsoap.org/wsdl/. Поэтому все элементы без префикса пространства имен, такие как message или portType , считаются частью пространства имен WSDL по умолчанию.
определяет многочисленные пространства имен, которые используются в оставшейся части документа.
ПРИМЕЧАНИЕ. – Спецификация пространства имен не требует, чтобы документ присутствовал в данном месте. Важным моментом является то, что вы указываете уникальное значение, отличное от всех других определенных пространств имен.
SOAP – Примеры
В приведенном ниже примере запрос GetQuotation отправляется на сервер SOAP через HTTP. Запрос имеет параметр QuotationName , и в ответе будет возвращено предложение.
Пространство имен для функции определяется по адресу http://www.xyz.org/quotation .
Вот SOAP-запрос –
Соответствующий SOAP-ответ выглядит так:
SOAP – структура сообщения
SOAP-сообщение – это обычный XML-документ, содержащий следующие элементы:
Конверт – определяет начало и конец сообщения. Это обязательный элемент.
Заголовок – содержит любые необязательные атрибуты сообщения, используемые при обработке сообщения, либо в промежуточной точке, либо в конечной конечной точке. Это необязательный элемент.
Тело – содержит данные XML, содержащие отправляемое сообщение. Это обязательный элемент.
Неисправность – необязательный элемент неисправности, который предоставляет информацию об ошибках, возникающих при обработке сообщения.
Все эти элементы объявлены в пространстве имен по умолчанию для конверта SOAP – http://www.w3.org/2001/12/soap-envelope, а пространство имен по умолчанию для кодировки SOAP и типов данных – http: //www.w3 .org / 2001/12 / мыла-кодирования
ПРИМЕЧАНИЕ. – Все эти характеристики могут быть изменены. Так что продолжайте обновлять себя новейшими спецификациями, доступными на сайте W3.
Атрибуты заголовка SOAP
Заголовок SOAP может иметь следующие два атрибута:
Протокол SOAP определяет путь сообщения как список узлов службы SOAP. Каждый из этих промежуточных узлов может выполнить некоторую обработку и затем переслать сообщение следующему узлу в цепочке. Устанавливая атрибут Actor, клиент может указать получателя заголовка SOAP.
Указывает, является ли элемент Header необязательным или обязательным. Если установлено значение true, получатель должен понимать и обрабатывать атрибут Header в соответствии с его определенной семантикой или возвращать ошибку.
В следующем примере показано, как использовать заголовок в сообщении SOAP.
5 Наш первый SOAP-сервер
Ранее я писал, что для создания SOAP-сервера на PHP мы будем использовать встроенный класс SoapServer. Для того, чтобы все дальнейшие действия происходили также как и у меня, вам понадобиться немного подкрутить свой PHP. Если быть еще точнее, то необходимо убедиться, что у вас установлено расширение «php-soap». Как его поставить на ваш веб-сервере лучше всего прочитать на официальном сайте PHP (см. список литературы).
После того, как все было установлено и настроено нам необходимо будет создать в корневой папке вашего хостинга файл «smsservice.php» со следующим содержанием:
То, что находится выше строчки с функцией «ini_set», надеюсь, что объяснять не надо. Т.к. там определяется какие HTTP-заголовки мы будем отправлять с сервера клиенту и настраивается окружение. В строчке с «ini_set» мы отключаем кеширование WSDL-файла для того, чтобы наши изменения в нем сразу же вступали в действие на клиенте.
Теперь мы подошли к серверу! Как видим, весь SOAP-сервер занимает всего лишь три строки! В первой строке мы создаем новый экземпляр объекта SoapServer и передаем ему в конструктор адрес нашего WSDL-описания веб-сервиса. Теперь мы знаем, что он будет располагаться в корне хостинга в файле с говорящим именем «smsservice.wsdl.php». Во второй строке мы сообщаем SOAP-серверу какой класс необходимо дергать для того, чтобы обработать поступивший с клиента конверт и вернуть конверт с ответом. Как вы могли догадаться, именно в этом классе будет описан наш единственный метод sendSms. В третьей строке мы запускаем сервер! Все, наш сервер готов! С чем я нас всех и поздравляю!
Теперь нам необходимо создать WSDL-файл. Для этого можно либо просто скопировать его содержимое из предыдущего раздела, либо позволить себе вольности и немного его «шаблонизировать»:
На этом этапе получившийся сервер нас должен устроить полностью, т.к. поступающие к нему конверты мы можем логировать и потом спокойно анализировать приходящие данные. Для того, чтобы мы могли что-либо получать на сервер, нам необходим клиент. Поэтому давайте им и займемся!
Коды ошибок SOAP
Определенные ниже значения faultCode должны использоваться в элементе faultcode при описании неисправностей.
Обнаружено недопустимое пространство имен для элемента конверта SOAP.
Непосредственный дочерний элемент элемента Header с атрибутом mustUnderstand, установленным в «1», не был понят.
Сообщение было неправильно сформировано или содержало неверную информацию.
Возникла проблема с сервером, поэтому сообщение не удалось продолжить.





