java 使用 CXF 时缺少 SoapAction 标头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17987443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 19:46:03  来源:igfitidea点击:

SoapAction header missing when using CXF

javaweb-servicesjax-wscxf

提问by mihn

I have a WSDL file from outside WS that i'm connecting to. And I'm trying to get it working with CXF (works fine with JAX-WS). But I'm getting error from other system. So I decided to take a look at data we're sending to that system and only diffrence is that CXF sets empty SOAPAction http header.

我有一个来自我要连接的 WS 外部的 WSDL 文件。我正在尝试让它与 CXF 一起工作(与 JAX-WS 一起工作正常)。但是我从其他系统收到错误。因此,我决定查看我们发送到该系统的数据,唯一的区别是 CXF 设置了空的 SOAPAction http 标头。

I took some reading and looks like only known solutions is pointing to WSDL directly. But I already did that.

我读了一些书,看起来只有已知的解决方案直接指向 WSDL。但我已经这样做了。

Anyone has a clue 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

回答by Patrick

None of this is CXF specific. It is all standard JAX-WS.

这些都不是 CXF 特定的。它都是标准的 JAX-WS。

You can use the action property of the @WebMethodannotation to set a SOAP action. For example

您可以使用@WebMethod注释的 action 属性来设置 SOAP 操作。例如

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

If you are using wsimportto generate artifacts from the WSDL, you should already have this set in your @WebServiceannotated interface.

如果您使用wsimport从 WSDL 生成工件,那么您应该已经在@WebService 带注释的接口中设置了这个。

回答by Alex

I was able to replicate the behavior you described (SOAPAction header is "") using an invocation like this:

我能够使用这样的调用来复制您描述的行为(SOAPAction 标头是“”):

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

Here are the HTTP Headers from TCP Dump using this invocation:

以下是使用此调用的 TCP Dump 的 HTTP 标头:

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 out interceptor and ensuring that the SOAPAction was set as a header, but no matter what I tried that did not cause the SOAPAction to be sent as part of the HTTP request.

我尝试添加一个 out 拦截器并确保将 SOAPAction 设置为标头,但无论我尝试什么都不会导致 SOAPAction 作为 HTTP 请求的一部分发送。

I then found a lead in this threadand reformatted my invocation:

然后我在这个线程中找到了一个线索并重新格式化了我的调用:

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 TCP Dump of an invocation in this style:

以下是这种风格调用的 TCP Dump 中的 HTTP 标头:

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.

希望这可以帮助。

回答by cynic

If it's still actual. Faced same problem and wrote interceptor. It's 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:

在 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>

回答by csturtz

I found another cause of this issue, so I thought I would go ahead and post this answer in case it helps someone.

我发现了这个问题的另一个原因,所以我想我会继续发布这个答案,以防它对某人有所帮助。

After creating a SOAP Service, WSDL-first, and generating the service interface and related classes from the XSD, I found that the soap action I was setting in my wsdl was not showing up in the CXF-generated WSDL (which you can get to by adding '?wsdl' to your service endpoint and putting that in your browser).

创建 SOAP 服务,WSDL-first,并从 XSD 生成服务接口和相关类后,我发现我在 wsdl 中设置的soap 操作没有显示在 CXF 生成的 WSDL 中(您可以访问通过将“?wsdl”添加到您的服务端点并将其放入您的浏览器中)。

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

例如:http://localhost:8080/mywar/services/myservice?wsdl

The cause of this issue for me was that I did not properly annotate the service implementation class. Although the generated interface had the appropriate annotations on it, the implementation class was the cause of my issue.

对我来说这个问题的原因是我没有正确注释服务实现类。虽然生成的接口上有适当的注释,但实现类是我问题的原因。

I had to add the following to my service implementation class to resolve the issue:

我必须将以下内容添加到我的服务实现类中以解决该问题:

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

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

Hope this helps someone...

希望这可以帮助某人...