Spring Boot SOAP Web服务响应Header添加及messageID传递求助
嘿,我来帮你搞定这个Spring Boot SOAP服务里传递messageID到响应Header的问题!你之前觉得消息拦截器不适用可变Header,其实是可以的——因为每个请求的上下文是独立的,完全能处理动态变化的messageID。下面给你两种可行方案,按需选择:
方案一:在端点方法中直接处理响应Header
如果你只需要在单个端点实现这个逻辑,直接在你的validationRequest方法里操作MessageContext就能完成:
步骤说明
- 从请求SOAP消息中解析出
messageID - 构造响应所需的
HeaderReply元素 - 将
HeaderReply添加到响应的SOAP Header中
修改后的端点代码
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getInput") @ResponsePayload public JAXBElement<GetResponse> validationRequest(@RequestPayload Element body, MessageContext context) throws SOAPException, XPathExpressionException { // 1. 解析请求Header中的messageID SaajSoapRequestMessage requestMessage = (SaajSoapRequestMessage) context.getRequest(); SOAPHeader requestHeader = requestMessage.getSaajMessage().getSOAPHeader(); // 使用XPath查找messageID节点(注意命名空间匹配) XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { if ("ns".equals(prefix)) { return "http://mynamespace.com/"; } return XMLConstants.NULL_NS_URI; } @Override public String getPrefix(String namespaceURI) { return null; } @Override public Iterator<String> getPrefixes(String namespaceURI) { return null; } }); Node messageIdNode = (Node) xpath.evaluate("//ns:HeaderRequest/messageID", requestHeader, XPathConstants.NODE); String messageId = messageIdNode.getTextContent(); // 2. 构造响应Header SaajSoapResponseMessage responseMessage = (SaajSoapResponseMessage) context.getResponse(); SOAPEnvelope envelope = responseMessage.getSaajMessage().getSOAPPart().getEnvelope(); SOAPHeader responseHeader = envelope.getHeader(); if (responseHeader == null) { responseHeader = envelope.addHeader(); } // 创建HeaderReply元素及子节点 SOAPElement headerReply = responseHeader.addChildElement("HeaderReply", "ns", "http://mynamespace.com/"); SOAPElement messageIdElement = headerReply.addChildElement("messageID"); messageIdElement.setTextContent(messageId); SOAPElement statusCodeElement = headerReply.addChildElement("statusCode"); statusCodeElement.setTextContent("200"); SOAPElement statusDescElement = headerReply.addChildElement("statusDescription"); statusDescElement.setTextContent("Success"); // 3. 返回响应体 JAXBElement<GetResponse> result = factory.createGetResponse(new GetResponse()); return result; }
方案二:使用全局消息拦截器(推荐多端点场景)
如果你的多个SOAP端点都需要传递messageID,用拦截器可以避免重复代码,全局统一处理:
步骤1:自定义端点拦截器
public class MessageIdHeaderInterceptor implements EndpointInterceptor { @Override public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception { // 提取请求的messageID,存入上下文属性供响应阶段使用 SaajSoapRequestMessage requestMessage = (SaajSoapRequestMessage) messageContext.getRequest(); SOAPHeader requestHeader = requestMessage.getSaajMessage().getSOAPHeader(); if (requestHeader != null) { XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { return "ns".equals(prefix) ? "http://mynamespace.com/" : XMLConstants.NULL_NS_URI; } @Override public String getPrefix(String namespaceURI) { return null; } @Override public Iterator<String> getPrefixes(String namespaceURI) { return null; } }); Node messageIdNode = (Node) xpath.evaluate("//ns:HeaderRequest/messageID", requestHeader, XPathConstants.NODE); if (messageIdNode != null) { messageContext.setProperty("REQUEST_MESSAGE_ID", messageIdNode.getTextContent()); } } return true; } @Override public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception { // 从上下文取出messageID,构造响应Header String messageId = (String) messageContext.getProperty("REQUEST_MESSAGE_ID"); if (messageId != null) { SaajSoapResponseMessage responseMessage = (SaajSoapResponseMessage) messageContext.getResponse(); SOAPEnvelope envelope = responseMessage.getSaajMessage().getSOAPPart().getEnvelope(); SOAPHeader responseHeader = envelope.getHeader(); if (responseHeader == null) { responseHeader = envelope.addHeader(); } SOAPElement headerReply = responseHeader.addChildElement("HeaderReply", "ns", "http://mynamespace.com/"); headerReply.addChildElement("messageID").setTextContent(messageId); headerReply.addChildElement("statusCode").setTextContent("200"); headerReply.addChildElement("statusDescription").setTextContent("Success"); } return true; } @Override public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception { // 异常场景也返回messageID和错误状态 String messageId = (String) messageContext.getProperty("REQUEST_MESSAGE_ID"); if (messageId != null) { SaajSoapResponseMessage responseMessage = (SaajSoapResponseMessage) messageContext.getResponse(); SOAPEnvelope envelope = responseMessage.getSaajMessage().getSOAPPart().getEnvelope(); SOAPHeader responseHeader = envelope.getHeader() == null ? envelope.addHeader() : envelope.getHeader(); SOAPElement headerReply = responseHeader.addChildElement("HeaderReply", "ns", "http://mynamespace.com/"); headerReply.addChildElement("messageID").setTextContent(messageId); headerReply.addChildElement("statusCode").setTextContent("500"); headerReply.addChildElement("statusDescription").setTextContent("Service fault occurred"); } return true; } @Override public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception { // 清理上下文属性(可选) messageContext.removeProperty("REQUEST_MESSAGE_ID"); } }
步骤2:在配置类中注册拦截器
修改你的WebConfig,重写addInterceptors方法添加自定义拦截器:
@EnableWs @Configuration public class WebConfig extends WsConfigurerAdapter { // ... 原有Bean配置保持不变 ... @Override public void addInterceptors(List<EndpointInterceptor> interceptors) { interceptors.add(new MessageIdHeaderInterceptor()); } }
关键注意点
- 命名空间匹配:确保代码中使用的命名空间(
http://mynamespace.com/)和你的WSDL、请求响应XML完全一致,否则会出现节点找不到的问题 - 异常处理:实际生产环境中建议添加空值判断(比如
messageIdNode可能为空的情况),避免空指针异常
内容的提问来源于stack exchange,提问作者gitau
相关产品推荐
相关产品推荐

