SpringBoot调用SOAP服务的请求响应拦截日志实现咨询
问题根因
你当前配置的EndpointInterceptor以及继承WsConfigurerAdapter的服务端配置,是Spring WS用于自身暴露SOAP服务端的拦截器逻辑,仅对接收外部SOAP请求的服务端生效。你现在的场景是作为客户端调用第三方SOAP服务,所以这套配置完全不会触发。
正确实现方案(适配你当前的JAX-WS原生客户端)
你用的是@WebClient注解标注的JAX-WS标准生成客户端,直接给端口对象绑定SOAP消息处理器即可实现请求响应日志记录。
步骤1:实现自定义日志SOAP处理器
import javax.xml.namespace.QName; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import java.io.ByteArrayOutputStream; import java.util.Collections; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SoapLogHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger log = LoggerFactory.getLogger(SoapLogHandler.class); @Override public Set<QName> getHeaders() { return Collections.emptySet(); } @Override public boolean handleMessage(SOAPMessageContext context) { // 判断是请求还是响应 boolean isOutbound = (boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage soapMessage = context.getMessage(); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { soapMessage.writeTo(baos); String soapContent = baos.toString("UTF-8"); if (isOutbound) { log.info("SOAP请求报文: {}", soapContent); } else { log.info("SOAP响应报文: {}", soapContent); } } catch (Exception e) { log.error("解析SOAP报文失败", e); } return true; // 返回true才会继续执行后续调用流程 } @Override public boolean handleFault(SOAPMessageContext context) { // 处理SOAP Fault错误报文 SOAPMessage faultMessage = context.getMessage(); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { faultMessage.writeTo(baos); log.error("SOAP错误报文: {}", baos.toString("UTF-8")); } catch (Exception e) { log.error("解析SOAP错误报文失败", e); } return true; } @Override public void close(MessageContext context) { // 无需额外逻辑 } }
如果运行时找不到javax.xml.ws相关类,可在pom中引入依赖:
<dependency> <groupId>javax.xml.ws</groupId> <artifactId>jaxws-api</artifactId> <version>2.3.1</version> </dependency>
步骤2:给客户端端口绑定处理器
修改你获取Producer端口的逻辑,添加处理器链即可:
// 你原来的业务方法里获取端口后添加 Producer p = serviceClient.getProducer(); // 绑定日志处理器 BindingProvider bindingProvider = (BindingProvider) p; List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain(); handlerChain.add(new SoapLogHandler()); bindingProvider.getBinding().setHandlerChain(handlerChain); // 后续正常调用接口 response = p.getData(request);
如果要全局生效不需要每次获取端口都加,也可以直接修改生成的ServiceClient类的getProducer方法,内部返回端口前就绑定处理器。
额外注意事项
- 如果SOAP报文包含敏感字段(比如密码、手机号),可以在
handleMessage方法里对报文内容做脱敏后再打印 - 生产环境可以根据日志级别控制是否打印报文,避免磁盘IO过高
- 报文里的特殊字符如果打印乱码,可以指定对应的编码格式,比如GBK等适配目标服务的编码
内容的提问来源于stack exchange,提问作者newcoder
相关产品推荐
相关产品推荐

