覆盖CXF错误处理

时间:2012-04-17 15:59:39

标签: java soap cxf

我正在开发一些基于Web服务的应用程序,我对Apache CXF解组有疑问。在我们的项目中,我们使用CXF 2.4.1版本。

当某些SOAP请求不正确时(例如某些字段是文本而不是数字),CXF会抛出标准的SOAPFaultException,并使用标准字段构建SOAP响应,如:

<soap:Fault>
    <faultcode>soap:Client</faultcode>
    <faultstring>Unmarshalling Error: some field missing</faultstring>
</soap:Fault>

项目要求说,如果出现任何故障,系统需要以其他格式响应,例如:

<soap:body>
    <ResponseState>
        <ErrorCode>2732</ErrorCode>
        <ErrorMessage>Unmarshalling Error: some field missing</ErrorMessage>
        <ErrorDetails> some details </ErrorDetails>
        <some other fields>
        ...
    </ResponseState>
</soap:body>

所以问题是:如何以某种方式覆盖此错误处理并以我的格式回复,而不是默认?

提前致谢。

P.S。我试图查看一些ValidationEventHandler主体,但它在CXF 2.0及更高版本中以其他方式工作。

3 个答案:

答案 0 :(得分:7)

好的,经过大量研究后我发现了一些CXF错误处理方法。

*。 ValidationEventHandler使您可以抛出自己的异常而不是标准异常。但是您无法更改响应行为,也无法更改SOAP响应格式。

*。另一种改变错误处理的方法是创建自己的拦截器。 CXF工作流程建立在拦截器链上。有4种类型的拦截器:inInterceptor,outInterceptor,inFaultInterceptor和outFaultInterceptor。

使用一些智能黑客,您可以通过创建自己的拦截器(将其添加到链)来更改工作流,并从链中删除标准拦截器(如果您知道它的类名)。所以你可以实际做任何你需要的事情。

但是就所有这些拦截器手动编组响应(xmlWriter.writeStartElement()等)而言,为每个流程阶段编写自己的拦截器可能是一个很大的挑战。这可能是真正的大量工作。

不幸的是,我还没有找到关于CXF拦截器的好参考。

另一件事 - 如果您需要返回常规响应而不是SOAPFaultException,您可能需要其他信息,例如:返回此响应的实际服务,请求中传递的服务参数等。我没有在拦截器中的可访问参数中找到此信息。并且,当然,通过这样做,您欺骗客户端代码将返回OK而不是真正的异常。

*。用所有参数设计你的wsdl作为文本可能是非常不好的解决方案:

一个。如果wsdl中没有数据类型和验证规则,那么您的服务的使用者可能会非常困惑。

湾你需要'重新发明轮子'进行验证。我的意思是你需要编写自己的验证器代码,这些验证器在一些复杂的规则下可能非常困难。与此同时,XSD已经实施了所有这些验证并进行了良好的测试。

最后关于我的情况:我们与需求管理器进行了讨论,并决定允许CXF在请求中违反XML模式要求时抛出自己的标准异常。这是一个很好的解决方案,因为现在我们正在使用XSD验证的所有功能,不要把时间浪费在复杂和无用的工作上。

非常感谢@ericacm的回答。

答案 1 :(得分:1)

您当然可以使用ValidationEventHandler生成比默认值更好的错误响应,并抛出符合JAX-WS Fault规范的Fault。但它只会让你进行如此多的定制 - 会有一些你无法控制的元素。例如,以下是我的某个应用程序的ValidationEventHandler响应:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>Errors in request</faultstring>
         <detail>
            <ns2:ValidationFault xmlns:ns2="http://notification.ws.foo.com/">
               <errors>
                  <error>
                     <inputElement>topicId</inputElement>
                     <errorMessage>java.lang.NumberFormatException: For input string: "" [line:6]</errorMessage>
                  </error>
               </errors>
            </ns2:ValidationFault>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

您无法对<soap:Fault>, <faultcode> and <faultstring>元素执行任何操作。但是从<ValidationFault></ValidationFault>的所有内容都是自定义的。

如果您需要对响应进行更详细的控制,那么您应该将字段类型从numeric更改为string,然后在代码中进行验证,而不是让unmarshaller捕获错误。

是的,我同意,强迫它成为一个字符串会很糟糕,但如果响应必须与上面所说的完全相同,那么如果不深入研究CXF而不是JAX-WS层(例如使用拦截器。)

答案 2 :(得分:0)

另一种选择是使用CXF Transform功能

<entry key="Fault" value="ResponseState=..."/>

这会将服务器的原始故障映射到任何其他故障,以便客户接受。