
Июнь 2004
Профессионалу разработчику
Бёнуа Маршаль (Benoit Marchal)
Передача файлов в Web-сервис
SOAP бинарные
данные
Источник: Журнал Intersoft Lab (перевод), 13-02-2004,
http://www.iso.ru/journal/articles/print/322.html
Оригинальный текст статьи:
Tip: Passing files to a Web service
В
этой статье ведущий колонки «Совет» (Tip)
рассматривает различные подходы, используемые для передачи бинарных данных
(обычно файлов) Web-сервис.
В
своем развитии протоколы Web-сервисов
прошли долгий путь, начиная поддержкой очень простых запросов с несложными
параметрами и заканчивая полной поддержкой современных объектно-ориентированных
языков. Спецификация XML-RPC (Удаленный вызов процедуры на XML),
являющаяся, пожалуй, одной из самых ранних форм Web-сервисов,
поддерживала только простые типы – строки, целые числа, логические выражения
и т.п. Следующим шагом явилось появление в SOAP правил
кодирования для объектов. Наконец, последний шаг – улучшение бинарного
кода - было введено в документе консорциума W3C "SOAP
с вложениями" (SOAP with attachments).
Первоначально "SOAP
с вложениями" был предложен в качестве расширения SOAP 1.1,
и сегодня эта технология поддерживается в большинстве инструментальных
средств SOAP.
Несмотря на то, что вложения пока не поддерживаются в официальной версии
спецификации W3C SOAP 1.2,
в настоящий момент ведутся работы с целью их включения в этот документ
в (умозрительно) ближайшем будущем.
Web-сервис
и бинарные данные
Автор
не испытывает ни малейших сомнений в том, что успех XML для
решения задач интеграции приложений связан с использованием текстового
кодирования (как противопоставления бинарным протоколам, как, например, CORBA,
объектно-ориентированному стандарту RPC, или RMI,
основанному на Java стандарту
RPC). Текстовое кодирование предпочтительно по нескольким причинам, наиболее
значимая из которых заключается в том, что в случае необходимости упрощается
отладка и развертывание конкретного приложении.
И
все же использование текстового кодирования имеет и свои «темные стороны»,
а XML не
располагает действенным способом включения бинарных данных. Согласно рекомендации
консорциума W3C «XML-схема»
(W3C XML Schema),
бинарные данные должен быть закодированы с использованием кода
Base-64 или шестнадцатеричного кода. К сожалению, размер данных, закодированных
с помощью шестибитного кода (Base-64), оказывается в полтора раза больше
по сравнению с размером незакодированных данных. Размер данных, преобразованных
в систему счисления с основанием 16, оказывается в два раза больше исходного.
Такие накладные расходы приемлемы в случае небольших фрагментов бинарных
данных, но для больших наборов данных такой подход неприемлем.
Вместе
с тем бинарные данные удобны для многих приложений, например:
- Для систем обеспечения безопасности
необходимы ключи, знаки "решетка", сертификаты, сами закодированные данные.
- Мультимедийные приложения
используют фото, музыку и фильмы.
- В некоторых приложениях применение XML-представления
оказывается неэффективным, например, в случае автоматизированного проектирования
(CAD)
или автоматизированного производства (CAM).
- Существуют тысячи файловых
форматов, которые появились до XML –
форматы текстовых процессоров, электронных таблиц, шрифтов, векторной
графики и т.д.
Хотя
создание XML-версий
этих файловых форматов возможно (аналогично формату SVG (Scalable
Vector Graphics, масштабируемая векторная графика) для векторной графики),
бинарные данные существуют уже давно и вряд ли потеряют популярность.
Наконец,
существуют проблемы и с самим XML!
Например, включение одного XML-документа
в другой XML-документ
не является тривиальной задачей (синтаксически корректное решение опирается
на разделы CDATA и переход на другие символы).
|
MIME и код base 64
Чтобы избежать часто возникающие недоразумения, подчеркнем,
что MIME не требует обязательного использования кодирования base 64.
Точнее реализации HTTP не кодируют включения; их кодируют только почтовые
клиенты, чтобы обойти ограничения SMTP (поэтому при сравнении с XML
каких-либо преимущества отсутствуют). |
Поэтому, чтобы реализовать требования всех этих приложений, Web-сервисы
должны эффективно поддерживать бинарные данные. Предлагаемое решение – SOAP
с вложениями, который, если попытаться сказать кратко, удаляет бинарную информацию
из полезной нагрузки XML и сохраняет ее непосредственно в запросе HTTP в
качестве содержания MIME multipart/related.
Таким образом, при проектировании Web-сервиса, который использует бинарные
данные, следует воспользоваться один из следующих подходов:
- Если набор данных невелик, можно использовать
код Base-64 для полезной нагрузки XML; накладные расходы для небольших
фрагментов данных не являются серьезной проблемой.
- Если набор данных значителен, включение – единственный
практически разумный выбор.
Ниже
приведен Листинг 1 (запрос SOAP с
параметром, закодированным
с помощью шестибитного кода,
в котором особого внимания заслуживает элемент address.
Листинг 1. Параметр в системе счисления с основанием 62
POST /ws/retrieve HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml multipart/related, text/*
Host: localhost:8080
SOAPAction: ""
Content-Length: 540
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ps:retrieve
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ps="http://psol.com/2004/ws/retrieve">
<address xsi:type="xsd:base64Binary">d3d3Lm1hcmNoYWwuY29t</address>
</ps:retrieve>
</soapenv:Body>
</soapenv:Envelope>
Реализация включений
Разработчики Java могут
воспользоваться включениями, используя JAX-RPC (API на Java для RPC, основанного
на XML) и SAAJ (API SOAP с включениями для Java). Читателю следует обратить
внимание на аббревиатуру SAAJ: JAX-RPC поддерживает включения (см., например, Ресурсы).
Различие между JAX-RPC и SAAJ заключается в уровне абстракции, а не в функциональных
возможностях.
JAX-RPC
– это API высокого
уровня, он более абстрактен по сравнению с SAAJ. JAX-RPC скрывает за слоем
протокола RMI (Remote
Method Invocation, технология построения распределенных приложений в спецификации
языка Java) большинство ориентированных на протокол аспектов SOAP.
Разработчик занимается объектами Java,
а препроцессор превращает их в узлы SOAP.
Для представления включений JAX-RPC использует
классы java.awt.Image и javax.activation.DataHandler.
SAAJ
более близок к протоколу. Поскольку для создания SOAP-сообщений
с помощью SAAJ требуется больше усилий, чем с JAX-RPC (и, следовательно,
он не предоставляет автоматических связей с WSDL),
в большинстве случае читатель отдаст предпочтение JAX-RPC. Вместе с тем,
низкоуровневые аспекты более удобны для иллюстрации того, как на самом
деле работают включения. Листинг 2 – это запрос SOAP с
включением. Этот запрос просит сервер изменить размер фотографии; поскольку
размер файла фотографии велик, использование включения более предпочтительно.
Листинг 2. Параметр
включения
POST /ws/resize HTTP/1.0
Content-Type: multipart/related; type="text/xml";
start="<EB6FC7EDE9EF4E510F641C481A9FF1F3>";
boundary="----=_Part_0_7145370.1075485514903"
Accept: application/soap+xml, multipart/related, text/*
Host: localhost:8080
SOAPAction: ""
Content-Length: 1506005
------=_Part_0_7145370.1075485514903
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <EB6FC7EDE9EF4E510F641C481A9FF1F3>
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ps:resize
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ps="http://psol.com/2004/ws/resize"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<source href="cid:E1A97E9D40359F85CA19D1B8A7C52AA3"/>
<percent>20</percent>
</ps:resize>
</soapenv:Body>
</soapenv:Envelope>
------=_Part_0_7145370.1075485514903
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-Id: <E1A97E9D40359F85CA19D1B8A7C52AA3>
note: binary data deleted...
------=_Part_0_7145370.1075485514903--
Приведенный
ниже Листинг 3 демонстрирует создание запроса SOAP.
Этот запрос просит сервер изменить размер изображения. Для реализации этой
процедуры необходимо выполнить следующую последовательность действий:
- Создать соединение SOAP и
объекты сообщения SOAP через
фабрики (factories).
- Извлечь тело сообщения из
объекта сообщения (промежуточный шаг: извлечь часть (part) SOAP и
конверт).
- Создать новый XML-элемент
для представления запроса и установить стиль кодирования.
- Создать включение и инициализировать
его с объектом DataHandler.
- Создать еще элементы для представления
двух параметров (source и percent).
- Ассоциировать включение с
первым параметром посредством добавления атрибута href. Ссылка на это
включение осуществляется через универсальный локатор ресурса cid (content-id).
- Задать значение второго параметра
непосредственно в виде текста и вызвать сервис.
Сервис
предоставляет ответ с изображением, размеры которого изменены, причем это
изображение представлено в виде включения. Чтобы извлечь его, можно протестировать SOAP на
предмет неисправности (т.е. ошибки). Если неисправностей нет, включение
следует извлечь в виде файла, а затем обработать.
Листинг
3. Использование SAAJ
public File resize(String endPoint,File file)
{
SOAPConnection connection =
SOAPConnectionFactory.newInstance().createConnection();
SOAPMessage message = MessageFactory.newInstance().createMessage();
SOAPPart part = message.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
SOAPBody body = envelope.getBody();
SOAPBodyElement operation =
body.addBodyElement(
envelope.createName("resize",
"ps",
"http://psol.com/2004/ws/resize"));
operation.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
DataHandler dh = new DataHandler(new FileDataSource(file));
AttachmentPart attachment = message.createAttachmentPart(dh);
SOAPElement source = operation.addChildElement("source",""),
percent = operation.addChildElement("percent","");
message.addAttachmentPart(attachment);
source.addAttribute(envelope.createName("href"),
"cid:" + attachment.getContentId());
width.addTextNode("20");
SOAPMessage result = connection.call(message,endPoint);
part = result.getSOAPPart();
envelope = part.getEnvelope();
body = envelope.getBody();
if(!body.hasFault())
{
Iterator iterator = result.getAttachments();
if(iterator.hasNext())
{
dh = ((AttachmentPart)iterator.next()).getDataHandler();
String fname = dh.getName();
if(null != fname)
return new File(fname);
}
}
return null;
}
Стоит
обратить внимание на то, что в Листинге 3 включение находится вне XML-сообщения.
Такой подход повышает производительность.
Говоря
о производительности, рассмотрим Листинг 4, в котором показана более общая
(и существенно более короткая) версия JAX-RPC Листинга
3. Прекомпилятор JAX-RPC генерирует переходник (stub),
которая значительно упрощает кодирование. В этом случае в качестве параметра
метода передается объект DataHandler,
а JAX-RPC автоматически генерирует это включение.
Листинг 4. Более
эффективный JAX-RPC
public File resize(File file)
throws ServiceException, RemoteException
{
AttachmentService service = new AttachmentServiceLocator();
AttachmentTip port = service.getAttachmentTip(); // get stub
DataHandler dh = new DataHandler(new FileDataSource(file));
DataHandler result = port.resize(dh,20);
return new File(result.getName());
}
Заключение
Возможность
выбора всегда желательна и SOAP предоставляет
такую возможность при работе с бинарными данными: их можно либо кодировать
с помощью кода base 64
внутри полезной нагрузки XML,
что является хорошим решением для небольших наборов данных, либо присоединять
более крупные бинарные незакодированные файлы к этому запросу.
Ресурсы
- Форум,
посвященный обсуждению статей в колонке Беноита Марчала (Benoît
Marchal) “XML в
действии” (Working XML).
- Для изучения SAAJ и JAX-RPC
можно скачать Axis.
Необходимо отметить, что для работы с включениями читателю потребуется
установить два дополнительных компонента: JavaMail и JavaBeans Activation Framework.
Автор хотел бы подчеркнуть, что включения не работают в Axos (версии
1.1 и 1.2), если эти две компоненты не установлены.
- Международный консорциум W3C ведет
работы над поддержкой вложений в SOAP 1.2
(attachment support to SOAP 1.2).
- Статья Рассела Бутека (Russell Butek)
«Отправка и получение сообщений SOAP с JAX-RPC»
("Send and receive SOAP messages with JAX-RPC")
(developerWorks,
сентябрь 2003 г.).
- В своей статье «Преобразование
типов Apache SOAP» (Apache SOAP type mapping)
Гевин Бонг (Gavin Bong) рассматривает соответствие между SOAP и
технологией Java.
Несмотря на то, что этот материал написан с позиции Apache SOAP, он применим
и к большинству инструментальных средств SOAP (developerWorks,
апрель 2002 г.).
- Ранняя версия (6.0) сервера
приложений IBM WebSphere
(IBM WebSphere Application Server Technology for Developers, version 6.0,),
поддерживающего последнюю редакцию спецификации J2EE (версию 1.4).
- Множество
других ресурсов в
зоне XML рубрики developerWorks.
Полный список статей колонки «Совет» (Tip)
приведен на странице
с кратким описанием этой рубрики.
- На странице информационный бюллетень
Web-cервисов/Советов по XMLможно подписаться на еженедельную рассылку
новостей рубрики developerWorks.
- Книга Беноита Марчала «Прикладные
решения XML»
(Applied XML Solutions)
можно приобрести в книжном магазине
разработчика рубрики developerWorks.
- На
странице IBM
Certified Developer in XML and related technologies приведена информация
о том, как стать сертифицированным разработчиком XML.
Об авторе
|
|
Бёнуа
Маршаль (Benoît Marchal) – бельгийский консультант. Он автор
многих книг, посвященных XML,
в том числе «XML на
примерах, второе издание» (XML by Example, Second Edition). Беноит
Марчал специализируется в области XML,
технологий Java и
электронной коммерции. Более подробную информацию о нем можно получить
на его сайте www.marchal.com. С
ним можно связаться по адресу bmarchal@pineapplesoft.com.
|
|