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

Spring WS MTOM自定义boundary被saveChanges覆盖如何解决

问题背景

Spring WS集成MTOM时,默认会强制将响应的Content-Type头设置为如下值:

Multipart/Related; boundary="----=_Part_9_1258512392.1655296193519"; type="application/xop+xml"; start-info="text/xml"

实际业务要求必须将boundary值修改为--uuid:something格式。
最初尝试通过实现EndpointInterceptor接口重写Content-Type头,实现代码如下:

public class RequestHandler implements EndpointInterceptor {


    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) {
        return true;
    }

    @Override
    public boolean handleResponse(MessageContext messageContext, Object endpoint) {
        this.setMTOM(messageContext);
        return true;
    }

    @Override
    public boolean handleFault(MessageContext messageContext, Object endpoint) {
        return true;
    }

    @Override
    public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) {
    }

    private void setMTOM(MessageContext messageContext) {
        String uri;
        try {
            uri = TransportContextHolder.getTransportContext().getConnection().getUri().toString();
        } catch (URISyntaxException e) {
            throw new LocalizedStatusException(INTERNAL_SERVER_ERROR, "messages.error_parsing_uri");
        }

        if (!uri.contains("no-mtom")) {
            String headerUUID = UUID.randomUUID().toString().strip();
            SaajSoapMessage response = (SaajSoapMessage) messageContext.getResponse();

            response.getSaajMessage().getSOAPPart().setContentId("<rootpart*" + headerUUID + "@example.jaxws.sun.com>");
            response.getSaajMessage().getMimeHeaders().setHeader(
                    HEADER_CONTENT_TYPE,
                    "Multipart/Related; boundary=\"uuid:" + headerUUID + "\"; start=\"<rootpart*" + headerUUID + "@example.jaxws.sun.com>\"; type=\"application/xop+xml\"; start-info=\"text/xml\"")
            ;
            response.getSaajMessage().getSOAPPart().setMimeHeader(
                    HEADER_CONTENT_TRANSFER_ENCODING,
                    "binary"
            );
        }

    }

}

该方案存在的问题是:拦截器逻辑执行完成后,SaajSoapMessage的saveChanges()方法会被框架自动调用,直接覆盖自定义设置的Content-Type头,导致配置不生效。

解决方案

EndpointInterceptor的执行时机早于消息序列化阶段,后续saveChanges()会根据MIME消息体的实际属性重新生成Content-Type头,直接在拦截器里设置头信息必然会被覆盖,可选择以下两种方案实现需求:

方案1:自定义SaajSoapMessageFactory,从数据源修改boundary配置

saveChanges()生成Content-Type时,会直接读取MimeMultipart实例的boundary字段作为头的参数值,直接修改这个字段的值,就能让最终生成的头符合要求,不会被覆盖。
扩展默认的SaajSoapMessageFactory,在消息写出前修改boundary属性即可:

public class UuidBoundarySaajSoapMessageFactory extends SaajSoapMessageFactory {
    @Override
    protected void writeTo(SaajSoapMessage message, OutputStream outputStream) throws IOException {
        try {
            MimeMessage saajMessage = message.getSaajMessage();
            String uuid = UUID.randomUUID().toString();
            MimeMultipart multipart = (MimeMultipart) saajMessage.getContent();
            // 反射修改MimeMultipart的boundary私有字段,这是生成Content-Type头的数据源
            Field boundaryField = MimeMultipart.class.getDeclaredField("boundary");
            boundaryField.setAccessible(true);
            boundaryField.set(multipart, "uuid:" + uuid);
            // 同步设置SOAP根节点的Content-ID,保证头里的start参数和实际内容匹配
            saajMessage.getSOAPPart().setContentId("<rootpart*" + uuid + "@example.jaxws.sun.com>");
            // 主动触发saveChanges,让框架基于修改后的配置生成头信息
            saajMessage.saveChanges();
            super.writeTo(message, outputStream);
        } catch (Exception e) {
            throw new IOException("Failed to set custom MTOM boundary", e);
        }
    }
}

将该自定义实现注册到Spring WS配置中,替换默认的SaajSoapMessageFactory即可生效。该方案无额外内存开销,适配大文件MTOM传输场景,优先选用。

方案2:通过Web过滤器在传输层替换最终响应头和内容

如果不想修改消息工厂逻辑,可以在Servlet层添加过滤器,缓存Spring WS生成的完整响应,待所有框架逻辑执行完成后,再替换Content-Type头和响应体里的分隔符:

  • 用HttpServletResponse包装类缓存响应流,避免响应提前写回客户端
  • 过滤器链执行完成后,读取缓存的响应内容,提取默认生成的boundary值
  • 将Content-Type头里的boundary替换为uuid:自定义UUID格式
  • 同步将响应体里所有用默认boundary生成的分隔符替换为新的boundary值,再写回真实响应

该方案需要缓存完整响应内容,MTOM传输大附件时内存开销较高,非必要不选择。


内容的提问来源于stack exchange,提问作者Tilo Papin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:18:24