You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Feign调用WebService无法提取含CID的二进制数据求助

解决方案:Feign调用WebService处理MTOM/XOP附件映射问题

问题根源是你的自定义SOAPDecoder未处理MTOM/XOP格式的附件解析,响应中xop:Include标签指向的cid对应MIME附件,但解码器没有将cid映射为实际二进制数据,导致_return字段为空。以下是具体解决步骤:

  • 启用Feign客户端的MTOM支持
    集成支持MTOM的SOAP消息工厂,比如Spring WS的SaajSoapMessageFactory,开启MTOM后才能解析MIME附件:

    @Bean
    public SaajSoapMessageFactory soapMessageFactory() {
        SaajSoapMessageFactory factory = new SaajSoapMessageFactory();
        factory.setMtomEnabled(true);
        return factory;
    }
    

    将该工厂注入自定义SOAPDecoder,让解码器具备MTOM处理能力。

  • 修改自定义SOAPDecoder,添加XOP附件解析逻辑
    原解码器仅解析SOAP Body的XML结构,需补充cid到二进制数据的映射逻辑。示例代码(基于Spring WS):

    public class CustomMTOMSOAPDecoder extends SOAPDecoder {
        private final SaajSoapMessageFactory messageFactory;
    
        public CustomMTOMSOAPDecoder(SaajSoapMessageFactory messageFactory) {
            this.messageFactory = messageFactory;
        }
    
        @Override
        public Object decode(Response response, Type type) throws IOException, DecodeException {
            // 将响应流转换为SOAP消息
            InputStream inputStream = response.body().asInputStream();
            SoapMessage soapMessage = messageFactory.createWebServiceMessage(inputStream);
    
            // 定位所有xop:Include节点
            Document document = soapMessage.getDocument();
            XPath xpath = XPathFactory.newInstance().newXPath();
            xpath.setNamespaceContext(new NamespaceContext() {
                @Override
                public String getNamespaceURI(String prefix) {
                    return "xop".equals(prefix) ? "http://www.w3.org/2004/08/xop/include" : XMLConstants.NULL_NS_URI;
                }
    
                @Override
                public String getPrefix(String namespaceURI) { return null; }
                @Override
                public Iterator<?> getPrefixes(String namespaceURI) { return null; }
            });
    
            NodeList includeNodes = (NodeList) xpath.evaluate("//xop:Include", document, XPathConstants.NODESET);
            for (int i = 0; i < includeNodes.getLength(); i++) {
                Element includeElement = (Element) includeNodes.item(i);
                String cid = includeElement.getAttribute("href").replace("cid:", "");
                // 根据cid获取对应附件
                Attachment attachment = soapMessage.getAttachment(cid);
                if (attachment != null) {
                    byte[] binaryData = FileCopyUtils.copyToByteArray(attachment.getInputStream());
                    // 将二进制数据替换xop节点内容(若JAXB接受Base64则编码,否则直接处理字节数组)
                    includeElement.setTextContent(Base64.getEncoder().encodeToString(binaryData));
                }
            }
    
            // 反序列化修改后的XML为AttachmentResponse
            JAXBContext jaxbContext = JAXBContext.newInstance(AttachmentResponse.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            return unmarshaller.unmarshal(new DOMSource(document));
        }
    }
    

    注意:需确保AttachmentResponse的_return字段对应的JAXB注解正确(如@XmlElement(name = "return")),且类型支持二进制数据(如byte[])。

  • 配置Feign请求头,指定MTOM格式
    在PersonProxy接口方法中添加请求头,告知服务端返回MTOM格式响应:

    @FeignClient(name = "personService", url = "${third-party.ws.url}", configuration = FeignMTOMConfig.class)
    public interface PersonProxy {
        @PostMapping(value = "/ws/person", consumes = "application/xop+xml", produces = "application/xop+xml")
        @Headers({
            "Content-Type: application/xop+xml; charset=utf-8; type=\"text/xml\"",
            "Accept: application/xop+xml; charset=utf-8; type=\"text/xml\""
        })
        AttachmentResponse getAttachment();
    }
    
  • 验证附件解析逻辑
    调试时可打印soapMessage.getAttachments()确认cid对应的附件存在,同时检查JAXB生成类的字段映射是否正确,确保二进制数据能正确注入_return字段。

内容的提问来源于stack exchange,提问作者Rohit yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 05:27:18