вторник, 1 декабря 2009 г.

Flex. Как правильно обработать ошибки SOAP веб-сервисов.

Программируя на Flex, как и везде, можно встретить массу интересных моментов. Иногда можно часами ломать голову о том, на что ты наткнулся: на ошибку или на фичу. Вот один из таких моментов хотелось бы описать.

Создание SOAP клиента и работа с SOAP веб-сервисами (SOAP Web Service) во Flex при использовании Flex Builder 3 - сплошное удовольствие, все делается в считанные минуты. В процессе работы с SOAP веб-сервисами в ответе вы можете получить сообщение об ошибке, тело самой ошибки будет помещено в атрибут SOAP Fault.

Для обработки ошибки добавляем слушателя события Fault.
private function onServiceFault(evt:FaultEvent): void {
   Alert.show("При получении данных произошла ошибка: " + evt.fault.faultString);
}
Но, как ни странно, при обработке ошибки во Flex приложении я получал сообщение: "HTTP request error". Оригинальное сообщение, которое было помещено в SOAP Fault в ответе веб-сервиса получить не удалось.

Много времени ушло на выяснения обстоятельств и на поиск откуда "растут ноги". Просмотрев код обработки SOAP клиента, я понял, что в случае когда Http Status ответа приходил 500, тело пакета не анализировалось и вызывалось событие mx.rpc.events.FaultEvent с mx.rpc.Fault ошибкой. Для решения необходим был Http Status 200, а само решение пришлось реализовать на серверной стороне в веб-сервисе.

Серверная часть была написана на Java и построена с использованием JAX-WS Reference Implementation. На мой взгляд, лучшим решением было написать свой handler-chain для веб-сервиса.

sun-jaxws.xml
<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
    <endpoint br="">        name='MyService'
        implementation='MySystem.services.MyService'
        url-pattern='/services/MyService'&gt;
        <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee">
            <javaee:handler-chain>
                <javaee:handler>
                    <javaee:handler-class>MySystem.services.MySOAPHandler</javaee:handler-class>
                </javaee:handler>
            </javaee:handler-chain>
        </javaee:handler-chains>
 </endpoint></endpoints>
MySOAPHandler.java
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.MessageContext.Scope;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;

public class MySOAPHandler implements SOAPHandler<soapmessagecontext> {

 public Set<qname> getHeaders() { 
  return null;
 }

 public void close(MessageContext context) {
  context.put(MessageContext.HTTP_RESPONSE_CODE, new Integer(200));
  context.setScope(MessageContext.HTTP_RESPONSE_CODE, Scope.APPLICATION);
 }

 public boolean handleFault(SOAPMessageContext context) {
  return true;
 }

 public boolean handleMessage(SOAPMessageContext context) {
  return true;
 }
После этих манипуляций на стороне клиента Flex можно обрабатывать SOAP Fault.
import mx.rpc.soap.SOAPFault;

private function onServiceFault(evt:FaultEvent): void {
   if (evt.fault is SOAPFault){
      var soapData:String = evt.fault.faultDetail;
      var soapError:String = evt.fault.faultString;
   } else {
      Alert.show("При получении данных произошла ошибка: " + evt.fault.faultString);
   }
}
Данный хак хоть и решает проблему, но требует дополнительных усилий. А вот если вы пользуетесь веб-сервисами других компаний, то вы можете столкнутся с "непреодолимым" барьером.

Комментариев нет:

Отправить комментарий