Как перехватить 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
Лучшая компания по разработке спортивных приложений
Лучшая компания по разработке спортивных приложений
Ищете лучшую компанию по разработке спортивных приложений? Этот список, несомненно, облегчит вашу работу!
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Blibli Automation Journey - Как захватить сетевой трафик с помощью утилиты HAR в Selenium 4
Если вы являетесь веб-разработчиком или тестировщиком, вы можете быть знакомы с Selenium, популярным инструментом для автоматизации работы...
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Фото ️🔁 Radek Jedynak 🔃 on ️🔁 Unsplash 🔃
Что такое Java 8 Streams API? Java 8 Stream API
Деревья поиска (Алгоритм4 Заметки к учебнику)
Деревья поиска (Алгоритм4 Заметки к учебнику)
(1) Двоичные деревья поиска: среднее lgN, наихудшее N для вставки и поиска.
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;
}

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