SoapAction header missing when using CXF

I have a WSDL file from external WS that I am connecting to. And I'm trying to get it to work with CXF (works fine with JAX-WS). But I get an error from another system. So I decided to take a look at the data we send to this system, and the only difference is that CXF sets an empty HTTP SOAPAction header.

I read a little and it seems that only well-known solutions directly point to WSDL. But I already did it.

Does anyone know about this?

<bean id="object" class="xxx.XxxObject" factory-bean="objectFActory" factory-method="create"/> <bean id="objectFActory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="xxx.XxxObject"/> <property name="wsdlLocation" value="http://blebleble"/> <property name="address" value="http://blebleble"/> <property name="username" value="user"/> <property name="password" value="password"/> <property name="properties"> <map> <entry key="javax.xml.ws.session.maintain" value-type="java.lang.Boolean" value="true"/> </map> </property> </bean> 

Headers:

 POST /somepath HTTP/1.1 Content-Type: text/xml; charset=UTF-8 Accept: */* Authorization: Basic <randomhex> SOAPAction: "" User-Agent: Apache CXF 2.7.6 Cache-Control: no-cache Pragma: no-cache Host: somehost:8080 Connection: keep-alive Content-Length: 2791 
+6
source share
4 answers

None of this has CXF. All standard JAX-WS.

You can use the @WebMethod annotation action property to set the SOAP action. for instance

 @WebMethod(operationName = "TestOperation", action="http://example.org/TestOperation") 

If you use wsimport to create artifacts from WSDL, you should already have this set in the @WebService annotated interface.

+8
source

I was able to reproduce the behavior you described (SOAPAction - "" header) with a call like this:

 MyPortService service = new MyPortService(); MyPort port = service.getMyPortSoap11(); MyRequest request = new MyRequest(); MyResponse response = port.subscription( request ); 

Here are the HTTP headers from the dump server using this call:

 POST /MyService/services HTTP/1.1 Content-Type: text/xml; charset=UTF-8 Accept: */* SOAPAction: "" User-Agent: Apache CXF 2.7.6 Cache-Control: no-cache Pragma: no-cache Host: redacted Connection: keep-alive Content-Length: 377 

I tried adding an interceptor and making sure that SOAPAction was set as the header, but no matter what I tried, that did not cause the SOAPAction to be sent as part of the HTTP request.

Then I found leadership in this thread and reformatted my call:

 ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); factory.setServiceClass( MyPort.class ); factory.setAddress( "http://www.host.com/service" ); factory.setServiceName( new QName( targetNamespace, wsdlBindingName ) ); Object myService = factory.create(); org.apache.cxf.endpoint.Client client = ClientProxy.getClient( myService ); Map<String, List<String>> headers = new HashMap<String, List<String>>(); headers.put("SOAPAction", Arrays.asList("mySoapAction")); client.getRequestContext().put(Message.PROTOCOL_HEADERS, headers); client.invoke( operationName, request ); 

Here are the HTTP headers from the dump dump call in this style:

 POST /MyService/services HTTP/1.1 Content-Type: text/xml; charset=UTF-8 Accept: */* SOAPAction: mySoapAction User-Agent: Apache CXF 2.7.6 Cache-Control: no-cache Pragma: no-cache Host: redacted Connection: keep-alive Content-Length: 377 

Hope this helps.

+3
source

If it is still relevant. Faced the same problem and wrote an interceptor. This is quite universal:

 public class SoapActionInterceptor extends AbstractSoapInterceptor { private static final String SLASH = "/"; public SoapActionInterceptor() { super(Phase.POST_LOGICAL); } @Override public void handleMessage(SoapMessage message) throws Fault { BindingOperationInfo bindingOperationInfo = message.getExchange().getBindingOperationInfo(); OperationInfo operationInfo = bindingOperationInfo.getOperationInfo(); InterfaceInfo interfaceInfo = operationInfo.getInterface(); QName interfaceInfoNameQName = interfaceInfo.getName(); QName operationQName = operationInfo.getName(); Map<String, List<String>> reqHeaders = CastUtils.cast((Map<?, ?>) message.get(Message.PROTOCOL_HEADERS)); if (reqHeaders == null) { reqHeaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); } if (reqHeaders.size() == 0) { message.put(Message.PROTOCOL_HEADERS, reqHeaders); } reqHeaders.put(SoapBindingConstants.SOAP_ACTION, Arrays.asList(interfaceInfoNameQName.getNamespaceURI() + SLASH + interfaceInfoNameQName.getLocalPart() + SLASH + operationQName.getLocalPart())); } } 

To use it in Spring + Apache CXF:

 <jaxws:client id="client" serviceClass="some.generated.webservice.Interface" wsdlLocation="/META-INF/wsdl/webservice.wsdl" address="http://example.address/service"> <jaxws:outInterceptors> <bean class="some.package.interceptor.SoapActionInterceptor"/> </jaxws:outInterceptors> </jaxws:client> 
+1
source

I found another reason for this problem, so I thought I would go ahead and post this answer if it helps someone.

After creating the SOAP service, first WSDL, and creating the service interface and its related classes from XSD, I found that the soap action that I set in my wsdl did not appear in the WSDL generated by CXF (which you can add by adding ' ? wsdl 'to your service endpoint and placing it in your browser).

ex: http: // localhost: 8080 / mywar / services / myservice? wsdl

The reason for this problem for me was that I did not correctly comment on the service implementation class. Although the generated interface had corresponding annotations, the implementation class was the cause of my problem.

I had to add the following to my service implementation class to solve the problem:

@WebService( targetNamespace="...", portName="...", endpointInterface="...", serviceName="...")

Hope this helps someone ...

0
source

Source: https://habr.com/ru/post/950791/


All Articles