【问题标题】:Catching the SOAP Fault error in custom interceptor (Soap12FaultOutInterceptor)在自定义拦截器中捕获 SOAP 错误错误 (Soap12FaultOutInterceptor)
【发布时间】:2013-05-07 17:59:48
【问题描述】:

我编写了一个自定义 CXF 拦截器来将所有 SOAP 请求和响应记录到数据库中,它似乎可以很好地处理正面测试用例和服务器错误。

但是当 SOAP 错误发生时,它只是忽略了我的拦截器并且没有记录任何内容。

自定义 CXF 拦截器。

public class DbLogOutInterceptor extends AbstractSoapInterceptor {

 public void handleMessage(SoapMessage message) {
    logger.info("Handling outbound request");

    String transaction = MDC.get(mdcKey);
    logger.info("OutBound Transaction ID : {} ", transaction);

     //code to log the SOAP message in database
    .......

     }
   }

我没有看到此方法的日志语句,而是看到了

 11:56:34,102 INFO  [Soap12FaultOutInterceptor] class org.apache.cxf.binding.soap.interceptor.Soap12FaultOutInterceptor$Soap12FaultOutInterceptor Internalapplication/soap+xml
 11:56:34,103 INFO  [EligibilityInfo] Outbound Message
 ---------------------------
 ID: 2
 Response-Code: 500
 Encoding: UTF-8
 Content-Type: application/soap+xml
 Headers: {}
 Payload :  

为了在我的自定义拦截器中捕获 SOAP 错误错误,我必须做些什么。

【问题讨论】:

  • 您能告诉我您是如何使用 CXF 的吗,即您是使用 Spring 和 CXF 还是仅仅将其用作 JAX-WS 提供程序?
  • 带有弹簧的CXF和拦截器使用CXF总线注册

标签: java soap cxf interceptor soapfault


【解决方案1】:

最好的方法是实现故障监听器并使用 org.slf4j.Logger 来记录错误消息,而不是使用 java 日志记录。

明智的做法是覆盖 LoggingInInterceptor 并编写您的自定义拦截器来获取请求负载。

public class CxfInputFaultInterceptor extends AbstractLoggingInterceptor {
private static final Logger LOG = LogUtils.getLogger(CxfInputFaultInterceptor.class);

public CxfInputFaultInterceptor() {
    super(Phase.RECEIVE);
}

第 1 步:cxf-beans.xml

    <cxf:bus>
    <cxf:inInterceptors>
        <ref bean="cxfInputFaultInterceptor"/>
    </cxf:inInterceptors>
    <cxf:inFaultInterceptors>
        <ref bean="cxfInputFaultInterceptor"/>
    </cxf:inFaultInterceptors>
    <cxf:properties>
        <entry key="org.apache.cxf.logging.FaultListener">
            <bean id="cxfFaultListener" class="pkg.common.ws.interceptor.CxfFaultListenerImpl" >
                <property name="loggedUser" ref="loggedUser"/>
            </bean> 
        </entry>
    </cxf:properties>
</cxf:bus>

第 2 步:你的监听器应该实现 org.apache.cxf.logging.FaultListener

import java.io.InputStream;

import org.apache.cxf.interceptor.LoggingMessage;
import org.apache.cxf.logging.FaultListener;
import org.apache.cxf.message.Message;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.InterfaceInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * Listener to faults on the processing of messages by CXF intercepter chain. Here we      override 
 * java.util.logging.Logger and use  org.slf4j.Logger to print error to console.
 */

public class CxfFaultListenerImpl implements FaultListener{

private static final Logger logger = LoggerFactory.getLogger(CxfFaultListenerImpl.class);
private static final String NEWLINE="\n";

public boolean faultOccurred(final Exception exception,final String description,final Message message) {

    createErrorLog(message);
    logger.error(" --------------------------------------------------------------------------------------------------");
    logger.error(" Stack Trace  :         ");
    logger.error(" --------------------------------------------------------------------------------------------------");
    logger.error(NEWLINE,exception);
    logger.error(" --------------------------------------------------------------------------------------------------");

    return true;
}

private void createErrorLog(final Message message){

     final Message inMessage = message.getExchange().getInMessage();

     final InputStream is = inMessage.getContent(InputStream.class);

     final EndpointInfo endpoint = message.getExchange().getEndpoint().getEndpointInfo();
     String logName=null;

     if(endpoint!=null && endpoint.getService()!=null){
         final String serviceName = endpoint.getService().getName().getLocalPart();
         final InterfaceInfo iface = endpoint.getService().getInterface();
         final String portName = endpoint.getName().getLocalPart();
         final String portTypeName = iface.getName().getLocalPart();
         logName =  serviceName + "."  + portName + "." + portTypeName;
     }
    final LoggingMessage buffer
    = new LoggingMessage("Error occured on Service Call  : "+NEWLINE +"----------------------------", logName);

    final Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE);
    if (responseCode != null) {
        buffer.getResponseCode().append(responseCode);
    }

    final String encoding = (String)message.get(Message.ENCODING);

    if (encoding != null) {
        buffer.getEncoding().append(encoding);
    }
    final String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
    if (httpMethod != null) {
        buffer.getHttpMethod().append(httpMethod);
    }
    final String ct = (String)message.get(Message.CONTENT_TYPE);
    if (ct != null) {
        buffer.getContentType().append(ct);
    }
    final Object headers = message.get(Message.PROTOCOL_HEADERS);

    if (headers != null) {
        buffer.getHeader().append(headers);
    }
    final String uri = (String)message.get(Message.REQUEST_URL);
    if (uri != null) {
        buffer.getAddress().append(uri);
        final String query = (String)message.get(Message.QUERY_STRING);
        if (query != null) {
            buffer.getAddress().append("?").append(query);
        }
    }

    final String requestXml= is.toString();
    if(requestXml !=null){
        buffer.getMessage().append("LoggedIn User:  ");
        buffer.getMessage().append(getCurrentUsername()+NEWLINE);
        buffer.getMessage().append("Request payload  : "+NEWLINE);
        buffer.getMessage().append(requestXml);
    }else{
        buffer.getMessage().append("LoggedIn User:  ");
        buffer.getMessage().append(getCurrentUsername()+NEWLINE);
        buffer.getMessage().append("No inbound request message to append.");
    }

    logger.error(buffer.toString());
}

}

希望仅在服务调用发生错误时才需要堆栈跟踪和有效负载的人,从而避免使用大量日志文件。

【讨论】:

    【解决方案2】:

    所以在我的自定义拦截器中,我编写了以下代码:

    Fault fault = new Fault(message.getContent(Exception.class));
    

    现在这是一些遗留代码,它们从 Java 中抛出异常并让框架将其转换为错误。我不会对此发表看法,但这会让你产生错误。

    现在,如果您的服务方法出现错误,请执行

    Fault fault = message.getContect(Fault.class);
    

    希望这将帮助您找到您想要的答案。确保你像下面这样注册拦截器

    <jaxws:endpoint
      id="fooService" implementor="com.bar.FooService" address="/FooServices">
      <jaxws:outFaultInterceptors>
            <ref class="com.bar.interceptor.DbLogOutInterceptor"/>
      </jaxws:outFaultInterceptors>
    </jaxws:endpoint>
    <jaxws:endpoint
    

    【讨论】:

    • 是否必须将我的自定义拦截器注册为 FaultInterceptors ?
    【解决方案3】:

    要捕获故障,您需要将拦截器注册为故障拦截器。例如

    <cxf:outFaultInterceptors>
       <bean class="DbLogOutInterceptor" />
    </cxf:outFaultInterceptors>
    

    有关使用 CXF 日志拦截器捕获输入/输出消息和输入/输出故障的示例,请参阅“使用自定义 CXF bean 元素启用消息日志记录”下的 CXF Configuration 页面。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-07
      • 2020-12-21
      • 2020-09-22
      • 2014-11-02
      • 2022-01-09
      • 1970-01-01
      • 2017-08-31
      • 1970-01-01
      相关资源
      最近更新 更多