【问题标题】:SoapAction header missing when using CXF使用 CXF 时缺少 SoapAction 标头
【发布时间】:2013-08-01 23:39:27
【问题描述】:

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

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

有人知道这件事吗?

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

标题:

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

【问题讨论】:

  • 唯一的区别是 CXF 设置了空的 SOAPAction http header。有效的请求(我假设为 JAX-WS)根本没有设置 SOAPAction HTTP 标头,还是将其设置为(非空)值?
  • JaxWS: SOAPAction: "获取" CXF: SOAPAction: ""
  • 唯一的方法可以帮助您了解问题的更多详细信息、与 cxf 一起使用的代码、wsdl 文件、您看到的标题...
  • JAX-WS 是规范。参考实现称为 JAX-WS RI(或 Metro)

标签: java web-services jax-ws cxf


【解决方案1】:

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

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

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

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

【讨论】:

  • 已设置,但未得到尊重。 ://
  • 您能否发布您正在使用的 WSDL,并注意您尝试调用的操作?另外,您如何通过 Spring 配置在 CXF 中创建客户端?以编程方式?
  • 嘿,久等了。我无法发布此 WSDL。我将其创建为 Spring bean,但不是使用 命名空间。
  • WSDL 中的 SOAP 操作值将覆盖您在 @WebMethod 注释中指定的值。您是否尝试从“objectFActory”定义中删除wsdlLocation,然后在@WebMethod 上使用action 属性?如果没有看到 WSDL,很难知道为什么 CXF 可能无法正确读取其 soapAction。
【解决方案2】:

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

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

以下是使用此调用的 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

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

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

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 );

以下是来自 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

希望这会有所帮助。

【讨论】:

  • 我希望有一些东西可以让 CXF 尊重 WSDL 操作设置。我已经编写了整个应用程序,只是想将 JAXWS 换成 CXF 来测试一些东西。
  • 对不起,我没有更好的答案 - 我通过拦截器和最终的流编写器调试了 CXF,但代码是一团糟,有大量无参数 + void 返回方法调用。我可以告诉 SOAPAction 标头在将其写入流之前一直保留在 Message 实例上,但无法确定 SOAPAction 被丢弃的原因。
  • 使用地图设置Message.PROTOCOL_HEADERS 是唯一适合我的编程解决方案。
【解决方案3】:

如果它仍然是真实的。面临同样的问题并编写了拦截器。它非常普遍:

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()));
    }
}

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

【讨论】:

    【解决方案4】:

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

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

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

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

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

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

    希望这对某人有所帮助...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      • 2023-03-26
      • 2013-02-15
      • 2016-07-15
      • 2013-08-19
      相关资源
      最近更新 更多