|
|
|
Описание для автора не найдено
|
|
|
|
|
|
|
|
Аргумент против SOAP кодирования
Автор: Tim Ewald, Корпорация Microsoft
(http://www.microsoft.com)
Перевод: Шатохина Надежда(sna@uneta.org), Ukraine .Net
Alliance (http://www.uneta.org)
Октябрь 2002
Применяется к:
Спецификации Web сервисов (SOAP, WSDL)
Обзор: Эта статья объясняет, почему SOAP
кодирование, также известное как "Section 5 encoding", является тенью от
прошлого SOAP, которому нет места в будущем Web сервисов.
Введение
Эволюция SOAP и Web сервисов
Суть проблемы
Конкретный пример
Решение проблемы кодирования
Будущее
Введение
SOAP – это краеугольный камень базового протокола Web сервисов. Спецификация
SOAP формализует использование XML сообщений в качестве средств связи. Она
определяет расширяемую модель, способ представить ошибки протокола и приложений,
правила для отправки сообщений через HTTP и рекомендации по преобразованию RPC
вызовов в SOAP сообщения. Очень полезно иметь стандартные пути для осуществления
этих задач. если их не будет, каждому разработчику, желающему послать XML
сообщения через HTTP, придется создавать собственные специальные решения этих
проблем, что крайне осложнит процесс взаимодействия. Большинство из
предлагаемого SOAP спецификацией полезно, но есть одна не очень хорошая вещь:
SOAP кодирование. SOAP кодирование – иногда называемое "Section 5 encoding", по
номеру раздела спецификации SOAP 1.1, в котором оно было определено – это тень
прошлого SOAP, которому нет места в будущем Web сервисов. Эта статья объясняет
почему, начиная с истории.
Эволюция SOAP и Web сервисов
Когда была написана первая спецификация SOAP, концепция Web сервисов
находилась еще на этапе становления. Люди планировали использовать SOAP в
качестве способа лучшего интегрирования технологий распределенных объектов,
таких как DCOM, CORBA и RMI, и Internet технологий, таких как XML и HTTP. Целью
было создать инфраструктуру, которая производит и потребляет сообщения,
основанные на XML, вместо различных двоичных форматов сообщений, предпочитаемых
каждой технологией (NDR, CDR и JRMP, соответственно).
Чтобы клиенты и серверы могли создавать и потреблять сообщения в
распределенных приложениях, им надо знать, как эти сообщения должны выглядеть.
Чтобы предоставить эту информацию, большинство распределенных объектных систем
используют комбинацию скомпилированного прокси/стаб/скелетон
(proxy/stub/skeleton) кода и двоичного представления метаданных (как Библиотеки
типов COM, Хранилища интерфейсов CORBA или файлы.class Java). SOAP не внес в это
никаких изменений. Авторы SOAP спецификации приняли, что разработчик приложения
будет гарантировать то, что клиенты и серверы имеют любую информацию,
необходимую для правильной обработки SOAP сообщений.
Однако авторы SOAP понимали, что если они не собираются определить общего
способа описания сообщений, они должны, по крайней мере, предоставить некоторые
рекомендации для того, как преобразовывать обычные объектно-ориентированные
программные конструкции в XML. Для решения этой проблемы они не могли
использовать XML Schema (XSD), она была еще далека от завершения. Поэтому они
определили модель данных на базе графов нетипизованных структур. Затем они
написали правила SOAP кодирования, которые объясняли, как сериализовывать
экземпляр модели данных SOAP в SOAP сообщение. Преобразование собственных
технологий в модель данных SOAP было оставлено за теми, кто будет реализовывать
SOAP.
Поскольку SOAP получил распространение в промышленности, возникли новые
требования. Разработчики хотят загружать описания форматов SOAP сообщений
серверов, чтобы можно было создавать клиентов для общения с ними. Поскольку
сервер, который хочет предоставлять такого рода описание, не может делать
никаких предположений о технологии, используемой для создания клиента, вскрытие
описаний сообщений с использованием существующего формата метаданных, такого как
Библиотека типов (Type Library), невозможно. Выходом из этой ситуации является
использование общего формата метаданных, такого же гибкого, как и сам SOAP, а
именно, WSDL. WSDL описывает поведение, поддерживаемое Web сервисом, с помощью
portTypes. portType – это коллекция операций. Операции определены в рамках
сообщений. Сообщения определены в рамках XML Schema. Сегодня для большинства
SOAP и WSDL довольно сложно взаимосвязаны; вместе с UDDI они определяют основные
строительные блоки Web сервисов.
Суть проблемы
Понимая, что XSD должно сыграть важную роль в описании SOAP сообщений, авторы
WSDL выбрали его (все-таки оставив дверь открытой для других вариантов).
Понимая, что уже существуют инструментальные средства, реализующие схему SOAP
кодирования, авторы спецификации WSDL были вынуждены тоже использовать ее.
Решение, к которому они пришли, было определять сообщения в рамках конструкций
XML схемы и затем разрешить связывание, чтобы применить к ним SOAP кодирование,
если понадобится.
Связывание определяет конкретные детали, которые вам надо знать, чтобы
вызывать операции, определенные portType. (Эта идея не нова. Например, классы
COM часто раскрывали свои методы через связывания vtable и
IDispatch. Подобным образом, методы класса CORBA обычно
доступны через статические заглушки или интерфейс динамического вызова.)
Создавая связывание WSDL, которое преобразовывает операции portType в SOAP
сообщения, посылаемые через HTTP, вы должны определить, содержат SOAP сообщения
литеральные или кодированные экземпляры конструкций схемы, используемых
операциями. Если вы выбираете "литеральные", вы говорите, что конструкции XML
Schema, которые используют ваши WSDL описания, являются конкретными
спецификациями того, что появится в теле вашего SOAP сообщения. Если вы
выбираете "кодированные", вы говорите, что конструкции XML Schema, которые
используют ваши WSDL описания, являются абстрактными спецификациями того, что
появится в теле вашего SOAP сообщения; их можно сделать конкретными, применяя
правила, определенные SOAP кодированием. (WSDL спецификация допускает
использование и других схем кодирования, но это происходит редко.)
Это подводит нас к сути проблемы. Как я объяснял ранее, схема SOAP
кодирования сериализует модели данных SOAP в XML. Как можно применять схему
кодирования для модели данных SOAP к абстрактным описаниям XML Schema, если одна
представляет информацию как граф нетипизованных структур, и другие - как дерево
типизованных элементов? К сожалению, ни спецификация SOAP (которая определяет
SOAP кодирование), ни спецификация WSDL (которая применяет ее для описаний XML
схемы) не отвечают на этот вопрос. Кстати, спецификации, описывающей что это
значит и как работает, вообще не существует. И это является проблемой.
Конкретный пример
До этого момента мои аргументы были лишь теоретическими, поэтому я представлю
пример, который поможет сделать их более практическими. Рассмотрим этот псевдо
код для операции Distance, которая измеряет расстояние между
двумя точками.
class Point
{
public Point() {}
public Point(int x, int y) { this.x = x; this.y = y; }
public int x;
public int y;
}
float Distance(Point p1, Point p2)
{
… // apply the Pythagorean Theorem
}
Вот WSDL документ, который описывает portType Geometry,
содержащий операцию Distance. Он также описывает привязку для
Geometry portType, который использует SOAP кодирование.
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.gotdotnet.com/team/tewald/sample"
targetNamespace=
"http://www.gotdotnet.com/team/tewald/sample">
<wsdl:types>
<xsd:schema targetNamespace=
"http://www.gotdotnet.com/team/tewald/sample">
<!-- Point type used by Distance operation -->
<xsd:complexType name="Point">
<xsd:sequence>
<xsd:element name="x" type="xsd:int" />
<xsd:element name="y" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<!-- RPC style message definitions -->
<wsdl:message name="DistanceInput">
<wsdl:part name="p1" type="tns:Point" />
<wsdl:part name="p2" type="tns:Point" />
</wsdl:message>
<wsdl:message name="DistanceOutput">
<wsdl:part name="result" type="xsd:float" />
</wsdl:message>
<!-- Geometry portType -->
<wsdl:portType name="Geometry">
<wsdl:operation name="Distance">
<wsdl:input message="tns:DistanceInput" />
<wsdl:output message="tns:DistanceOutput" />
</wsdl:operation>
</wsdl:portType>
<!-- Binding for Geometry portType that
uses SOAP encoding -->
<wsdl:binding name="GeometryBinding" type="tns:Geometry">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"
<wsdl:operation name="Distance">
<soap:operation soapAction="" style="rpc" />
<wsdl:input message="tns:DistanceInput">
<soap:body
namespace="http://www.gotdotnet/team/tewald/sample"
use="encoded" />
</wsdl:input>
<wsdl:output message="tns:DistanceOutput">
<soap:body
namespace="http://www.gotdotnet/team/tewald/sample"
use="encoded" />
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
</wsdl:definitions>
Представьте, что вы собираетесь реализовать сервис, который раскрывает этот
portType и привязку. Вы хотите, чтобы ваша реализация проверяла, что получаемые
ею от клиентов сообщения соответствуют формату, определенному WSDL. Если они не
совпадают, вы можете отказаться от них и возвратить ошибку без необходимости
что-либо делать. Итак, что составляет корректное сообщение?
Рассмотрим клиента, который передает два различных экземпляра
Point в качестве аргументов в операцию
Distance:
Point one = new Point(10, 20);
Point two = new Point(100, 200);
float f = proxy.Distance(one, two);
Вот сериализованное сообщение запроса клиента.
<soap:Envelope xmlns:soap=
"http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<ns:Distance xmlns:ns=
"http://www.gotdotnet.com/team/tewald/samples">
<p1>
<x>10</x>
<y>20</y>
</p1>
<p2>
<x>100</x>
<y>200</y>
</p2>
</ns:Distance>
</soap:Body>
</soap:Envelope>
На первый взгляд, кажется совершенно ясным, что каждый из экземпляров
p1 и p2 (названные по формальным параметрам к
ns:Distance) совпадает с описанием схемы для типа
Point в WSDL документе. Каждый из них имеет последовательность
двух элементов, x и y, значения которых целые
(integers). Но этот вывод не состоятелен. Пока модель данных SOAP для описания
конкретных значений, таких как x и y,
использует простые типы XML Schema (например, xsd:int), она не
использует для описания структурированных данных составные типы XML Schema (вот
почему я говорил, что модель данных SOAP основывается на нетипизированных
структурах). Если модель данных SOAP не использует составные типы, и SOAP
кодирование базируется на модели данных SOAP, благоразумно ли будет делать
вывод, что p1 и p2 являются SOAP кодированными
экземплярами составного типа Point?
Вы можете подумать, что я влезаю в дебри, как никак, p1 и
p2 ужасно похожи на Point. Итак, теперь
рассмотрим клиента, который передает тот же экземпляр Point, что и оба аргумента
при вызове операции Distance:
Point one = new Point(10, 20);
float f = proxy.Distance(one, one);
Вот сериализованное сообщение запроса клиента. В данном случает клиент
использует схему шифрования SOAP для "многоссылочных аксессоров", т.е. один
экземпляр Point (one) используется как оба параметра к
Distance, p1 и p2.
<soap:Envelope xmlns:soap=
"http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<ns:Distance xmlns:ns=
"http://www.gotdotnet.com/team/tewald/samples">
<p1 HREF="#id1"/>
<p2 HREF="#id1"/>
</ns:Distance>
<ns:Point id="id1"
xmlns:ns="http://www.gotdotnet.com/team/tewald/samples">
<x>10</x>
<y>20</y>
</ns:Point>
</soap:Body>
</soap:Envelope>
В данном случае очевидно, что p1 и p2 не
совпадают с описанием схемы для типа Point. Кстати, они даже не
подобны. Каждый из них имеет неопределенный атрибут href и ни в
одном из них нет обязательных дочерних элементов x и
y. Описание входного сообщения операции
Distance предлагает, что p1 и
p2 являются экземплярами Point, но очевидно,
что при наличии кодирования SOAP есть некоторые ситуации, в которых это не
так.
Итак, на чем мы остановились? Иногда элементы p1 и
p2 выглядят как сериализованные экземпляры
Point, а иногда нет. Теоретически, схема кодирования SOAP
должна предупреждать нас о том, как должны выглядеть p1 и
p2, за исключением случаев, когда нет определенного способа
применить схему кодирования SOAP к типам, определенным с использованием XML
Schema, таким как Point. При отсутствии такого определения,
реализовать сервер, который раскрывает Geometry portType и
привязку и гарантирует, что все получаемые им сообщения корректны, крайне
сложно.
Решение проблемы кодирования
Здесь вы, возможно, думаете, что это в действительности не ваша проблема,
потому что вы не реализовываете ваши Web сервисы с нуля. Вы используете
инструментальные средства Web сервиса и считаете, что они должны учитывать эти
детали вместо вас. Но это не решает проблемы; это просто передвигает ее от вас к
разработчикам инструментальных средств, которым придется решить, что делать. До
сих пор они обеспечивали поддержку для SOAP кодирования (несмотря на проблемы,
описанные мною в предыдущем разделе), но цена слишком высока. Большинство
инструментальных средств используют различные пути для литеральных и
кодированных привязок; по существу, реализовывая два уровня маршаллинга, по
одному на каждый случай. Среди разработчиков, которые потратили время, работая
над этой проблемой, бытует мнение, что нам нужно найти лучшее решение. Тем или
иным образом мы должны примирить SOAP кодирование и XML Schema.
К счастью, существует совершенно прямое решение. Правила SOAP кодирования
определяют превращение модели данных SOAP в XML сообщения. Нет смысла применять
SOAP кодирование для описаний в XML Schema, потому что между ними нет
установленных взаимоотношений. Но что будет, если вы напишете схему, которая
описывает XML сообщения, созданные SOAP кодированием?
Вот переработанное описание WSDL для Geometry portType,
который использует этот подход.
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.gotdotnet.com/team/tewald/sample"
targetNamespace=
"http://www.gotdotnet.com/team/tewald/sample">
<wsdl:types>
<xsd:schema targetNamespace=
"http://www.gotdotnet.com/team/tewald/sample">
<!-- Point type used by Distance operation,
note use optional attributes and
element content -->
<xsd:complexType name="Point">
<xsd:sequence minOccurs="0">
<xsd:element name="x" type="xsd:int" />
<xsd:element name="y" type="xsd:int" />
</xsd:sequence>
<xsd:attribute name="id"
type="xsd:ID" use="optional" />
<xsd:attribute name="href"
type="xsd:anyURI" use="optional" />
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<!-- RPC style message definitions -->
<wsdl:message name="DistanceInput">
<wsdl:part name="p1" type="tns:Point" />
<wsdl:part name="p2" type="tns:Point" />
</wsdl:message>
<wsdl:message name="DistanceOutput">
<wsdl:part name="result" type="xsd:float" />
</wsdl:message>
<!-- Geometry portType -->
<wsdl:portType name="Geometry">
<wsdl:operation name="Distance">
<wsdl:input message="tns:DistanceInput" />
<wsdl:output message="tns:DistanceOutput" />
</wsdl:operation>
</wsdl:portType>
<!-- Binding for Geometry portType that
uses SOAP encoding -->
<wsdl:binding name="GeometryBinding" type="tns:Geometry">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"
<wsdl:operation name="Distance">
<soap:operation soapAction="" style="rpc" />
<wsdl:input message="tns:DistanceInput">
<soap:body
namespace="http://www.gotdotnet/team/tewald/sample"
use="literal" />
</wsdl:input>
<wsdl:output message="tns:DistanceOutput">
<soap:body
namespace="http://www.gotdotnet/team/tewald/sample"
use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
</wsdl:definitions>
Обновленное описание типа Point включает в качестве
содержимого элемента типа описания двух новых атрибутов, id и
href, которые являются необязательными. Эти изменения в
Point обеспечивают возможность существования экземпляров,
эквивалентных тем, которые создавались SOAP кодированием при сериализации
многоссылочных данных. Экземпляр Point может включать атрибут
id и потомков элементов x и y
или атрибут href без потомков. Первое представляет экземпляр
Point; второе – ссылку на Point. Поскольку
описание XML Schema уже создало эквивалент SOAP кодирования, нет необходимости
применять к нему правила кодирования, таким образом, привязка для
Geometry portType обновлена для использования схемы литеральных
типов (атрибут encodingStyle был удален), следовательно,
устранена любая неоднозначности по поводу того, являются ли параметры операции
Distance, p1 and p2,
экземплярами Point.
Использует ли этот подход SOAP кодирование? Это зависит от вашей перспективы.
Выполняется, по существу, то же, что делает и SOAP кодирование без попытки
применить правила SOAP кодирования непосредственно к схеме, чем плохо. Ключевое
преимущество в том, что описание XML Schema, включенное в WSDL, точно описывает
сообщения, необходимые portType и привязке. Это значительно упрощает реализацию
сервиса, который перед обработкой сообщений проверяет их корректность.
Мы должны предпринять несколько шагов, чтобы получить широкую поддержку этого
подхода. Во-первых, нам надо определить стандартные, глобальные атрибуты для
представления ссылок на узлы в сериализованном графе. В моем примере я определил
локальные атрибуты id и href как часть типа
Point. Проблемой этого подхода является то, что каждый тип,
который может использоваться в сериализованном графе, должен определить
эквивалентные атрибуты с именно такой же семантикой. В противном случае,
инструментальным средствам придется принять, что любой тип, имеющий атрибуты
id и href, намеревается использовать их для
описания графа. Если мы создаем глобальные атрибуты и определяем типы, которые
их используют, нам не надо определять атрибуты для каждого типа, и
инструментальным средствам надо будет только распознать одну пару атрибутов. (В
The WS-I Basic Profile Working Group
(http://www.ws-i.org/docs/charters/WSBasic_Profile_Charter.pdf)
эта работа уже проделана при попытке помочь разрешить проблемы взаимодействия
Web сервисов, хотя эта работа еще не опубликована к моменту написания этой
статьи.)
Если стандартные глобальные атрибуты существуют, создатели инструментальных
средств могут позаимствовать их. Им придется внести, по существу, два изменения.
Во-первых, необходимо будет обновить их инструментарий WSDL, чтобы он мог
производить и потреблять XML Schemas, которые включают ссылочные атрибуты для
любого типа, который может использоваться для представления узла
сериализованного графа. Затем придется обновить инфраструктуру среды выполнения,
чтобы сериализовать и десериализовать дерево в XML сообщения, которые используют
эти атрибуты.
Будущее
Многие люди, включая и меня, верят, что уход от SOAP кодирования неизбежен.
Текущий проект спецификации SOAP 1.2 рабочей группы W3C XML Protocol делает
поддержку SOAP кодирования необязательной (т.е. инструментальные средства могут
соответствовать SOAP 1.2 без поддержки SOAP кодирования), текущий проект
рекомендаций по взаимодействию рабочей группы WS-I Basic Profile запрещает
использование SOAP кодирования с SOAP 1.1, и рабочая группа W3C Web Service
Description решила выбросить поддержку кодирования из их последнего рабочего
проекта спецификации WSDL 1.2.
Отражение этих изменений в инструментальных средствах займет некоторое время,
сначала мы должны обратиться к благоприятному для схемы способу сериализации
графов. Затем необходимо обновить инструментальные средства. На это понадобится
некоторое время, но ожидание того стоит. И наконец, будет намного проще
реализовывать и использовать стек Web сервисов.
Никакая часть настоящей статьи не может быть воспроизведена или
передана в какой бы то ни было форме и какими бы то ни было средствами, будь то
электронные или механические, если на то нет письменного разрешения владельцев
авторских прав.
Материал, изложенный в данной статье, многократно
проверен. Но, поскольку вероятность технических ошибок все равно существует,
сообщество не может гарантировать абсолютную точность и правильность приводимых
сведений. В связи с этим сообщество не несет ответственности за возможные
ошибки, связанные с использованием статьи.
|
|
|
|
|
|
|