Как перехватить XML-ответ Soap с недопустимым символом

Ошибка выглядит следующим образом: [com.ctc.wstx.exc.WstxLazyException] Недопустимый символьный объект: символ расширения (код 0x1a\r\n в [строке, столбце {неизвестный источник}]: [1,8035]

Это мой WebService в Springboot с его WebMethod, который получает массив полигонов, из которых одно из его полей содержит недопустимый символ:

@WebService(targetNamespace = "http://example.org.co/", name = "PolizaSoap")
@XmlSeeAlso({ObjectFactory.class})
public interface PolizaSoap {

@WebMethod(operationName = "Polizas", action = "http://example.org.co/Polizas")
@RequestWrapper(localName = "Polizas", targetNamespace = "http://example.org.co/", className = "com.example.Polizas")
@ResponseWrapper(localName = "PolizasResponse", targetNamespace = "http://example.org.co/", className = "com.example.PolizasResponse")
@WebResult(name = "PolizasResult", targetNamespace = "http://example.org.co/")
public ArrayOfPolizas Polizas(
    @WebParam(name = "param1", targetNamespace = "http://example.org.co/")
    java.lang.String param1,
    @WebParam(name = "param2", targetNamespace = "http://example.org.co/")
    java.lang.String param2,
    @WebParam(name = "param3", targetNamespace = "http://example.org.co/")
    java.lang.String param3
);
}

Я пробовал все виды перехватчиков (ClientInterceptor), фильтры (WebFilter), обработчики (SOAPHandler, HandlerInterceptor), и ни один из них не работал у меня, ошибка возникает мгновенно, и я не нашел способ получить ответ XML с недопустимым символом для можно модифицировать и так все работает.

Я начинаю думать, что это невозможно сделать, есть ли какая-либо другая альтернатива, которая не включает в себя просьбу поставщика ответов исправить это? Как я могу перехватить ответ XML с недопустимым символом (0x1a) без/до запуска исключения WebServiceException?

Обновлено: кто-нибудь знает, можно ли использовать FilterInputStream для исправления «XML», который поставляется с недопустимыми символами, прежде чем создавать исключение?

Если протокол требует, чтобы запрос был XML, а то, что получает ваша служба, не является XML, то ваш единственный способ действий — вернуть ошибку, указывающую, что запрос был неправильно сформирован. Вы должны стараться больше ничего не делать.

kjhughes 19.02.2023 01:24

Я согласен с @kjhughes. Ваше внимание должно быть сосредоточено на обнаружении неверных данных, диагностике того, откуда они поступают, и их исправлении в источнике. Попытка восстановить неверные данные в конечном счете отрицательно сказывается на надежности системы. Если кто-то отправляет вам неверные данные, вам следует решить, как устранить свою зависимость от этого источника данных.

Michael Kay 19.02.2023 01:32

Я понимаю, что модифицировать мыльный отклик не лучшее решение, но возможно ли? Было ли это сделано раньше с успехом? Что касается обработки ошибок, если я заставлю WebMethod выдавать исключение типа WebServiceException, я смогу его перехватить. Но все же, хотелось бы узнать, есть ли полное решение.

Olivetz 19.02.2023 01:46

@MichaelKay Я не могу устранить зависимость от источника данных, потому что это очень важная национальная организация для страховых компаний в моей стране. Должен быть способ.

Olivetz 19.02.2023 02:27

Нет, не обязательно иметь способ использовать XML-инструменты для данных, отличных от XML.

kjhughes 19.02.2023 03:45

@kjhughes, а почему я не могу перехватывать данные, отличные от XML, с помощью другой библиотеки или инструментов, чтобы получить данные?

Olivetz 19.02.2023 04:07

Конечно, вы можете использовать инструменты, отличные от XML, для данных, отличных от XML, но ваш вопрос касается SOAP, протокола на основе XML. Пока вы используете библиотеки на основе SOAP или XML, вам не следует ожидать помощи от этих библиотек для данных, отличных от XML. Если вы хотите работать на уровне HTTP, предварительно обработать данные в виде текста и попытаться восстановить данные в соответствии с нашими рекомендациями, вы можете это сделать. Однако самое большее, чем я мог бы помочь вам пойти по этому нерекомендованному пути, — это предложить Как разобрать недопустимый (плохой / неправильно сформированный) XML?, особенно вариант №1.

kjhughes 19.02.2023 04:52

Спасибо за ваш ответ, я посмотрю, что я могу сделать с этой информацией. Но этот вопрос все еще открыт для других решений...

Olivetz 19.02.2023 05:05

Похоже, что в начале ответа есть начальный символ. Лучший способ удаления будет похож на то, как я сделал бы это в С#. Сначала используйте программу чтения, отличную от xml, например StringReader, чтобы прочитать ответ, а затем удалите первые символы. Затем передайте StringReader в качестве входных данных в XmlReader.

jdweng 19.02.2023 10:08

Мне не совсем понятно, вызываете ли вы службу SOAP и получаете неверный ответ, или кто-то вызывает вашу службу SOAP и отправляет неверный запрос. Для последнего вы можете перехватить HTTP-запрос с помощью ServletFilter и манипулировать запросом как обычным текстом. Если вы вызываете службу, не находящуюся под вашим контролем, вы можете использовать HTTP-запрос низкого уровня для вызова службы SOAP без каких-либо библиотек SOAP. Затем вы получаете ответ в виде обычного текста, можете исправить ошибку, самостоятельно проанализировать XML и извлечь полезную нагрузку. Что-то вроде SoapUI можно использовать, чтобы показать вам низкоуровневый HTTP-запрос для вызова службы.

vanje 19.02.2023 14:12

@vanje Я вызываю внешнюю службу SOAP, проблема в том, что когда я получаю ответ, там есть недопустимый символ. У вас есть пример того, как его перехватить?

Olivetz 19.02.2023 21:10

@jdwengn Я пытался перехватить ответ, но не смог.

Olivetz 19.02.2023 21:11

Если вам нужно обрабатывать данные в формате, отличном от XML, то, конечно, это возможно. Просто не пытайтесь использовать XML-инструменты для работы.

Michael Kay 20.02.2023 09:04

@Olivetz: Вот пример вызова службы SOAP без библиотек SOAP: technology.amis.nl/soa/…

vanje 20.02.2023 11:06

@vanje выглядит хорошо! Я попробую этот подход

Olivetz 20.02.2023 16:03

@vanje Я пробовал, вроде работает!!!!!!!!

Olivetz 20.02.2023 17:44

@vanje Если хотите, создайте формальный ответ, и я отмечу вас как правильный ответ.

Olivetz 20.02.2023 18:13
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
17
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы вызываете внешнюю службу SOAP и получаете недопустимый XML в качестве ответа, и нет никаких шансов заставить провайдера исправить свою ошибку, то единственный вариант, который у вас есть, — это отказаться от стандартных библиотек SOAP и вызвать службу, используя низкоуровневую HTTP-функции, обработайте ответ как обычный текст и исправьте ошибку, а затем самостоятельно проанализируйте исправленный XML.

Вот пример вызова службы SOAP без библиотек SOAP (взято из https://technology.amis.nl/soa/how-to-call-a-call-a-webservice-directly-from-java-without -веб-сервис-библиотека/ )

public String getWeather(String city) throws MalformedURLException, IOException {
  //Code to make a webservice HTTP request
  String responseString = "";
  String outputString = "";
  String wsURL = "http://www.deeptraining.com/webservices/weather.asmx";
  URL url = new URL(wsURL);
  URLConnection connection = url.openConnection();
  HttpURLConnection httpConn = (HttpURLConnection)connection;
  ByteArrayOutputStream bout = new ByteArrayOutputStream();
  String xmlInput =
    " <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://litwinconsulting.com/webservices/\">\n" +
    " <soapenv:Header/>\n" +
    " <soapenv:Body>\n" +
    " <web:GetWeather>\n" +
    " <!--Optional:-->\n" +
    " <web:City>" + city + "</web:City>\n" +
    " </web:GetWeather>\n" +
    " </soapenv:Body>\n" +
    " </soapenv:Envelope>";
   
  byte[] buffer = new byte[xmlInput.length()];
  buffer = xmlInput.getBytes();
  bout.write(buffer);
  byte[] b = bout.toByteArray();
  String SOAPAction = "http://litwinconsulting.com/webservices/GetWeather";

  // Set the appropriate HTTP parameters.
  httpConn.setRequestProperty("Content-Length",
  String.valueOf(b.length));
  httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
  httpConn.setRequestProperty("SOAPAction", SOAPAction);
  httpConn.setRequestMethod("POST");
  httpConn.setDoOutput(true);
  httpConn.setDoInput(true);
  OutputStream out = httpConn.getOutputStream();

  //Write the content of the request to the outputstream of the HTTP Connection.
  out.write(b);
  out.close();
  //Ready with sending the request.
   
  //Read the response.
  InputStreamReader isr =
  new InputStreamReader(httpConn.getInputStream());
  BufferedReader in = new BufferedReader(isr);
   
  //Write the SOAP message response to a String.
  while ((responseString = in.readLine()) != null) {
    outputString = outputString + responseString;
  }
  
  //**************************************************************************************************** 
  // Here you have the response as plain text and you can apply your corrections
  //**************************************************************************************************** 

  //Parse the String output to a org.w3c.dom.Document and be able to reach every node with the org.w3c.dom API.
  Document document = parseXmlFile(outputString);
  NodeList nodeLst = document.getElementsByTagName("GetWeatherResult");
  String weatherResult = nodeLst.item(0).getTextContent();
  System.out.println("Weather: " + weatherResult);
   
  return weatherResult;
}

Другие вопросы по теме