将 UTF 字符处理为 JSON 时出现 ApacheCamel 异常。 (无效的 UTF-8 中间字节)

ApacheCamel exception while processing UTF char to JSON. (Invalid UTF-8 middle byte)

我们有一个 Camel 网关服务

现在在将对 POJO 的 SOAP 响应转换为 JSON 某处时抛出异常 下面,

com.ctc.wstx.exc.WstxLazyException: [com.ctc.wstx.exc.WstxLazyException] Invalid UTF-8 middle byte 
0x26 (at char #8412, byte #7999)

SOAP 响应带有一些 UTF 字符,例如“–”,这是导致问题的原因。 如何处理或忽略这些 UTF 字符并转换为 JSON?

骆驼代码:Routes.java

private void getPlanDetailsRequestRoute(JacksonDataFormat jacksonDataformat, SoapJaxbDataFormat soapJaxbDataFormat, DataFormat jaxb) {
        from("servlet:/PlanDetailsRequestService?matchOnUriPrefix=true").unmarshal(jacksonDataformat).to("dozer:transformOrder?mappingFile=DozerMapping.xml&sourceModel=com.ong.vx.gatewayservice.dto.PlanRecord&targetModel=com.ong.vx.gatewayservice.wsdl.GetPlanDetailsRequest").marshal(soapJaxbDataFormat)
                .to("bean:SoapEnvelopeWrapper?method=process").to(WS_URI).choice()
                .when(header(Exchange.HTTP_RESPONSE_CODE).isEqualTo(500)).to("bean:ExceptionExtracter?method=process")
                .endChoice().otherwise().unmarshal(soapJaxbDataFormat).end().unmarshal(jaxb).marshal().json(JsonLibrary.Jackson)
                .setHeader(Exchange.CONTENT_TYPE, constant("application/json"));
    }

异常:

com.ctc.wstx.exc.WstxLazyException: [com.ctc.wstx.exc.WstxLazyException] Invalid UTF-8 middle byte 0x26 (at char #8412, byte #7999)
at com.ctc.wstx.exc.WstxLazyException.throwLazily(WstxLazyException.java:40)
at com.ctc.wstx.sr.StreamScanner.throwLazyError(StreamScanner.java:724)
at com.ctc.wstx.sr.BasicStreamReader.safeFinishToken(BasicStreamReader.java:3758)
at com.ctc.wstx.sr.BasicStreamReader.getTextCharacters(BasicStreamReader.java:914)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleCharacters(StAXStreamConnector.java:327)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:191)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:415)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:386)
at org.apache.camel.converter.jaxb.JaxbDataFormat.unmarshal(JaxbDataFormat.java:255)
at org.apache.camel.dataformat.soap.SoapJaxbDataFormat.unmarshal(SoapJaxbDataFormat.java:284)
at org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:69)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:542)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.ChoiceProcessor.process(ChoiceProcessor.java:117)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:542)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:97)
at org.apache.camel.http.common.CamelServlet.doService(CamelServlet.java:195)
at org.apache.camel.http.common.CamelServlet.service(CamelServlet.java:74)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at 
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
atorg.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at 
org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.ctc.wstx.exc.WstxIOException: Invalid UTF-8 middle byte 0x26 (at char #8412, byte #7999)
at com.ctc.wstx.sr.StreamScanner.constructFromIOE(StreamScanner.java:640)
at com.ctc.wstx.sr.StreamScanner.loadMore(StreamScanner.java:1004)
at com.ctc.wstx.sr.BasicStreamReader.readTextSecondary(BasicStreamReader.java:4729)
at com.ctc.wstx.sr.BasicStreamReader.finishToken(BasicStreamReader.java:3802)
at com.ctc.wstx.sr.BasicStreamReader.safeFinishToken(BasicStreamReader.java:3756)
... 71 common frames omitted
Caused by: java.io.CharConversionException: Invalid UTF-8 middle byte 0x26 (at char #8412, byte #7999)
at com.ctc.wstx.io.UTF8Reader.reportInvalidOther(UTF8Reader.java:315)
at com.ctc.wstx.io.UTF8Reader.read(UTF8Reader.java:206)
at com.ctc.wstx.io.ReaderSource.readInto(ReaderSource.java:89)
at com.ctc.wstx.io.BranchingReaderSource.readInto(BranchingReaderSource.java:57)
at com.ctc.wstx.sr.StreamScanner.loadMore(StreamScanner.java:998)
... 74 common frames omitted

您收到的异常听起来像是 SOAP 响应的 UTF-8 字符被编码为 ISO-8859-1 而不是 UTF-8。另见 this answer for details

您是否检查过响应是否正确编码(根据 XML 声明?)并且响应的 charset header 是否正确?如果没有,最好修复 SOAP 服务(来源)。

如果您无法控制源代码,最好的办法可能是做一个 hacky 解决方法。例如,在转换之前使用正则表达式将分散注意力的字符替换为正确的字符。