【问题标题】:Disable Jax-WS Apache CXF HTTPConduit Message Logging禁用 Jax-WS Apache CXF HTTPConduit 消息日志记录
【发布时间】:2014-09-18 14:34:27
【问题描述】:

过去几天我一直卡在这个问题上,但无济于事,经过大量的谷歌搜索和反复试验后,我又回到了起点,没有运气。

我目前正在开发一个通过 JAX-WS 连接到第三方的 Java 应用程序。它们提供了一个 WSDL,我们使用 jaxws-maven-plugin 运行它来生成服务。通过 Spring 实现,HTTPConduit 然后用于更改端点并提供相关配置(例如密钥库)以连接到各种环境(例如 SysTest、UAT、生产等)。

问题是,我没有设置任何日志记录(实际上之前删除了两个拦截器),但是发送给第三方的 xml 消息出现在日志中。这是一个主要问题,因为我们正在向第三方发送信用卡信息,由于显而易见的原因,这些信息无法被记录。我可以更改 log4j 属性以防止以这种方式记录,但这不是解决办法。

下面是一些代码: 这是我们的 bean 文件。

<jaxws:client id="client1"
              xmlns:hsn="http://example.com"
              serviceClass="com.example.Service1"
              address="${service1.url}"
              endpointName="hsn:service1"/>

<jaxws:client id="client2"
              xmlns:hsn="http://example.com"
              serviceClass="com.example.Service2"
              address="${service2.url}"
              endpointName="hsn:service2"/>

<jaxws:client id="client3"
              xmlns:hsn="http://example.com"
              serviceClass="com.example.Service3"
              address="${service3.url}"
              endpointName="hsn:service3"/>

<http:conduit name="https://*/.*">
    <http:tlsClientParameters disableCNCheck="${service.disable-cn-check}">
        <sec:keyManagers keyPassword="${service.keystore.password}">
            <sec:keyStore type="JKS" password="${service.keystore.password}"
                          resource="${service.keystore.name}"/>
        </sec:keyManagers>
        <sec:trustManagers>
            <sec:keyStore type="JKS" password="${service.truststore.password}"
                          resource="${service.truststore.name}"/>
        </sec:trustManagers>
        <sec:cipherSuitesFilter>
            <sec:include>.*_EXPORT_.*</sec:include>
            <sec:include>.*_EXPORT1024_.*</sec:include>
            <sec:include>.*_WITH_DES_.*</sec:include>
            <sec:include>.*_WITH_AES_.*</sec:include>
            <sec:include>.*_WITH_NULL_.*</sec:include>
            <sec:exclude>.*_DH_anon_.*</sec:exclude>
        </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
    <http:client AutoRedirect="true" Connection="Keep-Alive"
                 ConnectionTimeout="${service.max-response-time}"
                 ReceiveTimeout="${service.max-response-time}"/>

</http:conduit>

<http:conduit name="http://*/.*">
    <http:client AutoRedirect="true" Connection="Keep-Alive"
                 ConnectionTimeout="${service.max-response-time}"
                 ReceiveTimeout="${service.max-response-time}"/>
</http:conduit>

如您所见,没有日志拦截器或使用以下命令显式打开日志记录:

<cxf:bus>
    <cxf:features>
        <cxf:logging/>
    </cxf:features>
</cxf:bus>

我能想到的唯一其他相关文件是 META-INF/cxf/org.apache.cxf.Logger,其中包含:

org.apache.cxf.common.logging.Slf4jLogger

即使没有文件也不会进行任何更改。

您可以看到,这里也是日志中的一个示例:

15:05:45.742 DEBUG | org.apache.cxf.phase.PhaseInterceptorChain  - Invoking handleMessage on interceptor org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor@5e62b59d
15:05:45.742 DEBUG | org.apache.cxf.transport.http.Headers  - Accept: */*
15:05:45.743 DEBUG | org.apache.cxf.transport.http.Headers  - Connection: Keep-Alive
15:05:45.743 DEBUG | org.apache.cxf.transport.http.Headers  - SOAPAction: ""
15:05:45.744 DEBUG | org.apache.cxf.transport.http.HTTPConduit  - No Trust Decider for Conduit '{http://example.com}service1.http-conduit'. An afirmative Trust Decision is assumed.
15:05:45.746 DEBUG | org.apache.cxf.transport.http.HTTPConduit  - Sending POST Message with Headers to http://localhost:8080/stubs/Service1 Conduit :{http://example.com}service1.http-conduit

15:05:45.746 DEBUG | org.apache.cxf.transport.http.HTTPConduit  - Conduit "{http://example.com}service1.http-conduit" Transmit cached message to: http://localhost:8080/stubs/Service1: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>********************HERE LIES THE XML MESSAGE*********************</soap:Body></soap:Envelope>
15:05:45.766 DEBUG | org.apache.cxf.endpoint.ClientImpl  - Interceptors contributed by bus: [org.apache.cxf.ws.policy.PolicyInInterceptor@24ec87dc]
15:05:45.767 DEBUG | org.apache.cxf.endpoint.ClientImpl  - Interceptors contributed by client: []
15:05:45.767 DEBUG | org.apache.cxf.endpoint.ClientImpl  - Interceptors contributed by endpoint: [org.apache.cxf.jaxws.interceptors.WrapperClassInInterceptor@52d1f1fb, org.apache.cxf.jaxws.interceptors.HolderInInterceptor@5565c037, org.apache.cxf.jaxws.interceptors.SwAInInterceptor@b2e86ae, org.apache.cxf.frontend.WSDLGetInterceptor@1ca801a2]
15:05:45.768 DEBUG | org.apache.cxf.endpoint.ClientImpl  - Interceptors contributed by binding: [org.apache.cxf.interceptor.AttachmentInInterceptor@1b8c0f3e, org.apache.cxf.interceptor.StaxInInterceptor@83cbd93, org.apache.cxf.binding.soap.interceptor.SoapActionInInterceptor@4bc2021e, org.apache.cxf.interceptor.DocLiteralInInterceptor@2e19266d, org.apache.cxf.binding.soap.interceptor.SoapHeaderInterceptor@7529d5bf, org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor@d902ab1, org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor@73e2d16b, org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor@3023033d, org.apache.cxf.binding.soap.interceptor.MustUnderstandInterceptor@4aa9b27b]
15:05:45.768 DEBUG | org.apache.cxf.endpoint.ClientImpl  - Interceptors contributed by databinging: [org.apache.cxf.jaxb.attachment.JAXBAttachmentSchemaValidationHack@331fef77]
15:05:45.769 DEBUG | org.apache.cxf.phase.PhaseInterceptorChain  - Chain org.apache.cxf.phase.PhaseInterceptorChain@273221e was created. Current flow:
  receive [PolicyInInterceptor, AttachmentInInterceptor]
  post-stream [StaxInInterceptor]
  read [WSDLGetInterceptor, ReadHeadersInterceptor, SoapActionInInterceptor, StartBodyInterceptor]
  pre-protocol [MustUnderstandInterceptor]
  post-protocol [CheckFaultInterceptor, JAXBAttachmentSchemaValidationHack]
  unmarshal [DocLiteralInInterceptor, SoapHeaderInterceptor]
  post-logical [WrapperClassInInterceptor]
  pre-invoke [SwAInInterceptor, HolderInInterceptor]

15:05:45.769 DEBUG | org.apache.cxf.phase.PhaseInterceptorChain  - Invoking handleMessage on interceptor org.apache.cxf.ws.policy.PolicyInInterceptor@24ec87dc

【问题讨论】:

  • 您在 SLF4J 中使用什么 Logging 实现?日志4J?看起来您为 CXF 启用了调试日志记录,这就是输出消息的原因。我会在类路径的某处寻找 log4j.properties,或者为您的日志框架提供等效的配置文件。
  • SLF4J。我们有一个属性文件,所以我自然可以更改通用日志记录级别或添加类似 log4j.logger.org.apache.cxf=ERROR 的内容,因此 cxf 只会在错误级别记录。然而,这种方法掩盖了问题,而不是完全停止记录。
  • 如果您将 HTTPConduit 的日志记录设置为 DEBUG 级别,CXF 将记录 HTTP 流量。阻止它的唯一方法是将级别设置为其他值。我认为这不是问题,因为 DEBUG 通常确实包含比通常记录的更多信息,并且在生产应用程序上禁用 DEBUG 日志记录是很常见的。唯一的其他选择是更改 CXF 代码。

标签: java spring logging cxf jax-ws


【解决方案1】:

只需在你的类路径中添加 logback.xml 文件,记录级别为 INFO,它将禁用 CXF DEBUGS 的所有输出。

示例文件

文件名:logback.xml 位置:src/main/resources(在我的项目它的资源中,您可以将文件相应地放置在您的项目类路径中)

文件内容:

<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
    <resetJUL>true</resetJUL>
</contextListener>

<!-- To enable JMX Management -->
<jmxConfigurator/>

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

<logger name="com.mycompany.subpackage" level="INFO"/>

<root level="INFO">
    <appender-ref ref="console"/>
</root>

【讨论】:

    【解决方案2】:

    几个月前我遇到了类似的问题,我需要屏蔽我的 xml 的几个字段

    CustomLoginInterceptor

    import org.apache.commons.lang3.StringUtils;
    import org.apache.cxf.interceptor.LoggingInInterceptor;
    import org.apache.cxf.interceptor.LoggingMessage;
    
    public class KPLogInInterceptor extends LoggingInInterceptor {
    
        @Override
        protected String formatLoggingMessage(LoggingMessage loggingMessage) {
    
            String str = loggingMessage.toString();
    
            String output = maskPasswords(str);
            //output = maskRestPasswords(output);
            return(output);
        }
    
    
        private String maskPasswords(String str) {
    
            // String str =
                    // "<password1>asdasdad</password1><Password3></Password3><Password5/><PassWord6>fdsfsf</PassWord6>";
                    final String[] keys = { "password", "authpass", "accountnumber", "authphrase" };
                    for (String key : keys) {
                        int beginIndex = 0;
                        int lastIndex = -1;
                        boolean emptyPass = false;
                        boolean multiline = false;
                        if(key.equals("authphrase") || key.equals("authpass"))
                        {
                           //when lines are in multiplelines say <name>authphrase</name><value>vals</value>
                            multiline = true;
                        }
                        while (beginIndex != -1
                                && (beginIndex = StringUtils.indexOfIgnoreCase(str, key,
                                        beginIndex)) > 0) {
    
                            if(multiline){
                                beginIndex = StringUtils.indexOfIgnoreCase(str, "value", beginIndex);
                            }
                            beginIndex = StringUtils.indexOf(str, ">", beginIndex);
                            if (beginIndex != -1) {
                                char ch = str.charAt(beginIndex - 1);
                                if (ch == '/') {
                                    emptyPass = true;
                                }
                                if (!emptyPass) {
                                    lastIndex = StringUtils.indexOf(str, "<", beginIndex);
                                    if (lastIndex != -1) {
                                        String overlay = "*";
                                        String str2 = StringUtils.substring(str,
                                                beginIndex + 1, lastIndex);
                                        if (str2 != null && str2.length() > 1) {
                                            overlay = StringUtils.rightPad(overlay,
                                                    str2.length(), "*");
                                            str = StringUtils.overlay(str, overlay,
                                                    beginIndex + 1, lastIndex);
                                        }
                                    }
                                }
                                if (emptyPass) {
                                    emptyPass = false;
                                    lastIndex = beginIndex + 1;
                                } else {
                                    if (lastIndex != -1) {
                                        lastIndex = StringUtils
                                                .indexOf(str, ">", lastIndex);
                                    }
                                }
                            }
                            beginIndex = lastIndex;
                        }
                    }
                    return str;
    
                }
    }
    

    还有 cxf 配置 xml

    <bean id="kpInInterceptor" class="com.kp.swasthik.KPLogInInterceptor"></bean>
    <bean id="kpOutInterceptor" class="com.kp.swasthik.KPLogOutInterceptor"></bean>
    
        <cxf:bus>
            <cxf:inInterceptors>
                <ref bean="kpInInterceptor" />
            </cxf:inInterceptors>
            <cxf:outInterceptors>
                <ref bean="kpOutInterceptor" />
            </cxf:outInterceptors>
            <cxf:outFaultInterceptors>
                <ref bean="kpOutInterceptor" />
            </cxf:outFaultInterceptors>
            <cxf:inFaultInterceptors>
                <ref bean="kpInInterceptor" />
            </cxf:inFaultInterceptors>
        </cxf:bus>
    

    您需要再创建一个扩展 LogOutInterceptor 的类

    编辑

    创建将日志级别设置为 INFO 的类

    public class KPLogicSupresser {
    
        public void kpinit(){
    
            LogManager.getLogger(HTTPConduit.class).setLevel(Level.INFO);
    
    
        }
    
    
    }
    

    并在CXF配置文件中创建一个bean

    <bean id="kpLog4Jsupresser" class="com.kp.swasthik.KPLogicSupresser" init-method="kpinit" ></bean>
    

    【讨论】:

    • 很遗憾不起作用。添加拦截器时,它们只是创建另一层日志记录,而不是替换 CXF 提供的现有日志记录。
    • @CrazyDino 添加了一个肮脏的把戏。但是我觉得这应该由 CXF 团队解决,我认为一次又一次地在多个地方打印有效载荷不是一个好主意。有效负载已经在 logininterceptor 中打印
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2013-08-23
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多