J'utilise Spring Boot avec Apache CXF. Le démarreur que cxf-spring-boot-starter-jaxws
est la botte à ressort cxf-spring-boot-starter-jaxws
. J'ai suivi les guides du site Web d'Apaches cxf. http://cxf.apache.org/docs/springboot.html
.
J'utilise également Java11.
Le problème que je rencontre est que le savon demande à l'application que l'erreur renvoie toujours 200 en-têtes, qu'il y ait eu une erreur ou non.
Le point de terminaison du service Web que je frappe est une méthode vide, mais je voudrais toujours renvoyer un code 500 dans l'en-tête http si cela ne fonctionne pas.
La stratégie que j'ai à l'esprit est de créer un intercepteur qui interceptera les demandes de savon cette erreur et modifiera la réponse finale avec un code d'en-tête http. Ainsi, le corps serait nul pour les méthodes void mais l'en-tête est 400 ou 500.
Ma configuration de service de savon ressemble à ceci
Interceptor for {http://xyz/}SoapEventEndpointService#{http:/xyz}ReceiveEvent has thrown exception, unwinding now org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"http://xyz", local:"EventId1"). Expected elements are <{http://xyz}LocalAssessmentId>,<{http://xyz}LOTId>,<{http://xyz}EventId>,<{http://xyz}Benefit> at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:938) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:744) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:172) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:194) ~[cxf-rt-wsdl-3.3.1.jar:3.3.1] at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[cxf-core-3.3.1.jar:3.3.1] at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[cxf-core-3.3.1.jar:3.3.1] at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:216) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:301) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:220) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:276) ~[cxf-rt-transports-http-3.3.1.jar:3.3.1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.16.jar:9.0.16] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] Caused by: javax.xml.bind.UnmarshalException: null at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:483) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:417) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:394) ~[jaxb-runtime-2.3.1.jar:2.3.1] at org.apache.cxf.jaxb.JAXBEncoderDecoder.doUnmarshal(JAXBEncoderDecoder.java:887) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at org.apache.cxf.jaxb.JAXBEncoderDecoder.access$200(JAXBEncoderDecoder.java:103) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at org.apache.cxf.jaxb.JAXBEncoderDecoder$3.run(JAXBEncoderDecoder.java:926) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na] at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:924) ~[cxf-rt-databinding-jaxb-3.3.1.jar:3.3.1] ... 51 common frames omitted Caused by: com.sun.istack.SAXParseException2: unexpected element (uri:"xyz", local:"EventId1"). Expected elements are <{http://xyz}LocalAssessmentId>,<{http://xyz}LOTId>,<{http://xyz}EventId>,<{http://xyz}Benefit> at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:257) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:124) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.childElement(Loader.java:105) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.childElement(StructureLoader.java:268) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:556) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:246) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:180) ~[jaxb-runtime-2.3.1.jar:2.3.1] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:415) ~[jaxb-runtime-2.3.1.jar:2.3.1] ... 57 common frames omitted Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://uxyz", local:"EventId1"). Expected elements are <{http://xyz}LocalAssessmentId>,<{http://xyz}LOTId>,<{http://xyz}EventId>,<{http://uxyz}Benefit> ... 68 common frames omitted 2019-03-27 15:44:15.245 DEBUG 22552 --- [nio-8080-exec-4] o.a.c.t.http.AbstractHTTPDestination : Finished servicing http request on thread: Thread[http-nio-8080-exec-4,5,main] 2019-03-27 15:44:15.245 DEBUG 22552 --- [nio-8080-exec-4] o.a.c.t.servlet.ServletController : Finished servicing http request on thread: Thread[http-nio-8080-exec-4,5,main]
Intercepteurs
@WebService(targetNamespace = "xyz", name = "ReceiveEventEndpoint") @XmlSeeAlso({ObjectFactory.class}) @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) public interface ReceiveEventEndpoint { @WebMethod(operationName = "ReceiveEvent", action = "xyz") @Oneway public void receiveEvent( @WebParam(partName = "in", name = "ReceiveEventRequest", targetNamespace = "xyz") ReceiveEventRequest in ); }
WSDL vers point de terminaison d'événement généré par Java
@Slf4j public class SoapFaultInterceptor extends AbstractSoapInterceptor { public SoapFaultInterceptor(String phase) { super(phase); } @Override public void handleMessage(SoapMessage message) throws Fault { log.info("THIS NEVER GETS CALLED!! Execpting errors to invoke this method"); } } @Slf4j public class SoapInterceptor extends AbstractSoapInterceptor { public SoapInterceptor(String p){ super(p); } @Override public void handleMessage(SoapMessage message) throws Fault { log.info("THIS WORKS"); } }
1) Lorsque j'invalide avec le XML et envoie la demande. Seul le SoapInterceptor
intercepte? Le SoapFaultInterceptor
pas? Aucune suggestion?
@Configuration @Slf4j public class WebServiceConfiguration { @Autowired private Bus bus; @Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(bus, new SoapEventEndpoint()); endpoint.publish("/EventEndpoint"); endpoint.setWsdlLocation("ReceiveEvent.wsdl"); // this interceptor works endpoint.getInInterceptors().add(soapInterceptor()); // these two fault interceptors do not work! endpoint.getInFaultInterceptors().add(soapFaultInterceptor()); endpoint.getOutFaultInterceptors().add(soapFaultInterceptor()); return endpoint; } @Bean public AbstractSoapInterceptor soapFaultInterceptor(){ return new SoapFaultInterceptor( Phase.PRE_STREAM); } @Bean public AbstractSoapInterceptor soapInterceptor(){ return new SoapInterceptor( Phase.PRE_STREAM); } }
** 2) Comment puis-je ajouter un intercepteur (ou un écouteur de défauts) ou une autre méthode pour mettre à jour l'en-tête http après l'interception des erreurs?
3 Réponses :
Avez-vous essayé quelque chose comme ceci:
@Override public void handleFault(Message message) { Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS); try { headers.put("Status", "500"); ... } catch (Exception ce) { ... } }
Ce qui suit a fonctionné pour moi: dans la classe package-info.java
dans project, j'ai changé:
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED
Dans l'interface ReceiveEventEndpoint
, la méthode receiveEvent
est annotée avec l'annotation @OneWay
qui signifie qu'elle n'a qu'un message d'entrée et aucune sortie (y compris les défauts).
Vous pouvez trouver plus de détails ici Comprendre l'annotation @Oneway dans JAX-WS , http://cxf.547215.n5.nabble.com/Detecting-unmarshalling-error-with-Oneway-operations-td5742536.html et http: // cxf.547215.n5.nabble.com/OneWay-interpretation-and-HTTP-binding-td5711719.html
Pour des raisons de débogage, si vous devez lever des erreurs dans les opérations OneWay, vous pouvez ajouter la propriété Message.ROBUST_ONEWAY à votre point de terminaison:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Client</faultcode> <faultstring>Unmarshalling Error: unexpected element (uri:"http://xyz", local:"EventId1")...</faultstring> </soap:Fault> </soap:Body> </soap:Envelope>
Pour les demandes non valides, vous obtiendrez un HTTP 500 avec le corps suivant sans avoir besoin d'ajouter un intercepteur personnalisé:
@Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(bus, new SoapEventEndpoint()); endpoint.publish("/EventEndpoint"); endpoint.setWsdlLocation("ReceiveEvent.wsdl"); // interceptors... //To throw exceptions in OneWay messages Map<String, Object> prop = new HashMap<>(); prop.put(Message.ROBUST_ONEWAY, true); endpoint.setProperties(prop); return endpoint; }
Pouvez-vous essayer de remplacer handleFault ()?
bon cri ... j'ai essayé ça et ça n'a pas marché
Donc, la première partie fonctionne maintenant ... J'avais juste besoin d'ajouter le handleFault comme vous l'avez suggéré. Cependant, il devait être injecté avant la phase de marshal, pas après ... Je suppose que le prochain défi à résoudre est de savoir comment ajouter un en-tête http