Статьи

Проверка полезной нагрузки JAX-WS и проблемы Websphere 7

Файл WSDL содержит ссылку на документ XSD, который определяет структуры данных, которые могут быть отправлены службе через SOAP. В XSD вы можете определить тип для элемента или такие элементы, как количество элементов, будь то необязательный или обязательный, и т. Д.

Когда вызывается веб-сервер, на котором размещается веб-служба, он получает конверт SOAP, который сообщает ему, какой веб-сервис называется Он может (и вы, возможно, ожидаете) проверять тело сообщения SOAP с XSD в WSDL … но это не так.

Это плохо? Что ж, большинство клиентов будут генерироваться из WSDL, поэтому вы можете предположить, что безопасность типов соблюдается. Сказав это, сервер не может гарантировать, поэтому он должен проверить, что, скажем, поле, которое должно содержать дату, действительно содержит дату, а не какой-то искаженный текст, который должен быть датой. Но что еще более важно, то, что клиент не гарантирует, состоит в том, присутствуют ли все обязательные поля в структуре данных. Чтобы проверить это, вы можете проверить входящие тела SOAP на соответствие XSD.

Способ сделать это, используя «Обработчики». Спецификация JAX-WSопределяет два вида, а именно, обработчики SOAP и логические обработчики. Тип SOAP полезен для доступа к необработанному конверту SOAP, например, для регистрации фактического сообщения SOAP. Логический вид полезен для доступа к полезной нагрузке в виде XML-документа. Чтобы настроить обработчик, вы добавляете аннотацию HandlerChain в свой веб-сервис, передавая ему имя файла конфигурации обработчика:

@WebService
@HandlerChain(file="handler.xml")
public class GislerService {

  private static final String FORMAT_DD_MMM_YYYY_HH_MM_SS = "dd. MMM yyyy HH:mm:ss";

  @WebMethod
  public String formatDate(ObjectModel om){
    SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DD_MMM_YYYY_HH_MM_SS);
    return "Formatted, its " + sdf.format(om.date);
  }
}

Таким образом, чтобы проверить тело в соответствии с XSD (т. Е. Чтобы убедиться, что экземпляр «ObjectModel» в вышеприведенном методе является действительным до того, как ваш метод будет вызван средой WS), вы используете логический обработчик, чтобы получить полезную нагрузку как javax.xml.transform.Source и передайте его в javax.xml.validation.Validator, который вы создадите с помощью javax.xml.validation.SchemaFactory и javax.xml.validation.Schema, основанных на XSD из WSDL. Если проверка прошла успешно, вы позволяете своему обработчику возвращать «true», в противном случае вы генерируете исключение javax.xml.ws.WebServiceException, передавая ему текст исключения проверки, чтобы любой клиент, сделавший недопустимый вызов, мог понять, почему он недействителен. Это что-то вроде этого:

public class MyLogicalHandler implements LogicalHandler {

  private Validator validator;

  public MyLogicalHandler(){
    try{
      long start = System.nanoTime();					
      SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
      Schema schema = schemaFac.newSchema(new URL("http://localhost:8084/Gisler/GislerServiceService?xsd=1"));
      validator = schema.newValidator();
      System.out.println("created validator in " + ((System.nanoTime()-start)/1000000.0) + "ms");
    } catch (IOException e) {
      e.printStackTrace();
      throw new WebServiceException(e.getMessage());  //cant validate/initialise
    } catch (SAXException e) {
      e.printStackTrace();
      throw new WebServiceException(e.getMessage());  //cant validate/initialise
    }
  }
.
.
.
  public boolean handleMessage(LogicalMessageContext context) {

    if (((Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue()) {
      return true; // only validate incoming messages
    }

    try{
      LogicalMessage lm = context.getMessage();
      Source payload = lm.getPayload();
      validator.validate(payload);
      System.out.println("validated ok");
    }catch(SAXParseException e){
      System.out.println("validated failed: " + e.getMessage());
      throw new WebServiceException(e.getMessage());  //invalid, so tell the caller!
    } catch (SAXException e) {
      e.printStackTrace();
      throw new WebServiceException(e.getMessage());  //cant validate/initialise
    } catch (IOException e) {
      e.printStackTrace();
      throw new WebServiceException(e.getMessage());  //cant validate/initialise
    }
		
    return true;
  }
}

В
присоединенных проектах Eclipse , были протестированы с использованием GlassFish v3 (GlassFish Tools Bundle для Eclipse , 1.2), и они работали хорошо. Чтобы проверить обязательные, но отсутствующие элементы, я написал тест JUnit, который находится в проекте клиента. Чтобы проверить неверно сформированные даты, я перехватил HTTP-запросы SOAP от JUnit с помощью монитора Eclipse TCP / IP и изменил их перед повторной отправкой, указав недопустимую строку даты. Обратите внимание, что для этого вам также нужно изменить «длину содержимого» заголовка HTTP с помощью монитора, в противном случае вы получите очень странные ошибки, потому что поток заканчивается рано! Альтернативой является использование такого инструмента, как SoapUI.

По сравнению со Glassfish, Websphere не очень хорошо справился — в него встроена неприятная функциональность. Проверка с использованием обработчика работает нормально, пока не поступит ваш первый недействительный запрос. Затем он все еще работает, пока не будет обработан другой действительный запрос. После этого он полностью игнорирует недопустимые элементы, такие как даты, если они помечены как необязательные (по умолчанию!). Как придешь? Ну, это заняло некоторое время, но в основном это оптимизирует входящее сообщение, утверждая, что если элемент является необязательным и присутствует, но недействителен, недействительные данные могут быть выброшены, потому что это … хорошо, необязательно … Хорошо, я тоже не мог поверить, но это то, что он делает, обработчик SOAP, который регистрирует в System.out, просто пропустил недопустимый элемент. Так что немного поискать в интернете, и немного удачи,и эй Престо это
ссылка, которая является исправлением ошибки для пакета исправлений Websphere 7 9. Устанавливая системное свойство «jaxws.payload.highFidelity = true», Websphere гарантирует, что сообщение, передаваемое обработчикам, является точно тем, которое пришло по проводам. Испытания показали, что это действительно решило проблему.

Так что же все это значит в общей схеме SOAP? Что ж, при разработке службы вам необходимо учитывать, насколько важно иметь достоверные данные. Если вы разрешите необязательные поля, которые строго типизированы, такие как даты или сложные типы, у вас могут возникнуть проблемы. Без добавления проверяющего обработчика, возможно, что вызывающая сторона передаст вам необязательные, но недействительные данные, и вы не получите их в своем веб-сервисе, которому дается нулевая ссылка вместо недействительных данных! Если вы не работаете с необязательными данными, вы можете пропустить проверку и просто позволить исключениям нулевого указателя летать в случаях, когда вызывающая сторона передала недопустимые требуемые данные. Записывая входящие и исходящие сообщения, это облегчает отладку таких проблем,но немного невежливо создавать общедоступный интерфейс, который обрабатывает недопустимые запросы, подобные этому.

Последнее соображение — это производительность. Создание валидатора для простой схемы, как в этой демонстрации, заняло всего около 20 мс на моем ноутбуке. Фактическая проверка заняла менее миллисекунды для правильного запроса и чуть более миллисекунды для неверного ответа. Читатель остаётся сделать собственные выводы ?

От http://blog.maxant.co.uk/pebble/2010/09/09/1284065640000.html