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

如何使用RestTemplate发送含Atom条目与文件的multipart/related请求

解决RestTemplate发送multipart/related请求的部件头部自定义与请求构建问题

针对你的两个疑问,我来一步步帮你解决:

一、如何修改各请求部件的头部信息

当然可以自定义每个multipart部件的头部!问题出在你之前直接把JAXB对象和文件资源放进LinkedMultiValueMap,这时候RestTemplate会使用默认的头部规则。要自定义每个部件的Content-Type、Content-ID等,你需要把每个部件包装成带有独立HttpHeaders的HttpEntity,这样就能精准控制每个部分的头部信息。

二、正确构建multipart/related请求的完整实现

下面是调整后的完整代码,同时解决你提到的Atom部件Content-Type错误和文件部件添加Content-ID的问题:

1. 配置RestTemplate的消息转换器

首先要确保FormHttpMessageConverter支持multipart/related类型,并且JAXB消息转换器能处理application/atom+xml:

RestTemplate restTemplate = new RestTemplate();

// 让FormHttpMessageConverter支持multipart/related
restTemplate.getMessageConverters().stream()
    .filter(FormHttpMessageConverter.class::isInstance)
    .map(FormHttpMessageConverter.class::cast)
    .findFirst()
    .ifPresent(converter -> {
        List<MediaType> supportedTypes = new ArrayList<>(converter.getSupportedMediaTypes());
        supportedTypes.add(MediaType.MULTIPART_RELATED);
        converter.setSupportedMediaTypes(supportedTypes);
    });

// 确保JAXB转换器支持application/atom+xml(用于正确序列化你的Atom对象)
restTemplate.getMessageConverters().stream()
    .filter(Jaxb2RootElementHttpMessageConverter.class::isInstance)
    .map(Jaxb2RootElementHttpMessageConverter.class::cast)
    .findFirst()
    .ifPresent(converter -> {
        List<MediaType> supportedTypes = new ArrayList<>(converter.getSupportedMediaTypes());
        supportedTypes.add(new MediaType("application", "atom+xml"));
        converter.setSupportedMediaTypes(supportedTypes);
    });

2. 构建带自定义头部的请求部件

分别为Atom XML和文件创建带独立头部的HttpEntity:

// 构建Atom XML部件:设置Content-Type为application/atom+xml
HttpHeaders atomHeaders = new HttpHeaders();
atomHeaders.setContentType(new MediaType("application", "atom+xml"));
HttpEntity<YourAtomEntryClass> atomPart = new HttpEntity<>(e, atomHeaders); // e是你的JAXB Atom对象

// 构建文件部件:设置Content-Type和Content-ID
HttpHeaders fileHeaders = new HttpHeaders();
fileHeaders.setContentType(MediaType.parseMediaType("video/mp2t"));
fileHeaders.setContentId("<prod@example.com>"); // 注意Content-ID的格式
HttpEntity<FileSystemResource> filePart = new HttpEntity<>(new FileSystemResource(file), fileHeaders);

3. 组装并发送请求

把部件放进LinkedMultiValueMap,设置请求的Content-Type为multipart/related并指定类型参数:

LinkedMultiValueMap<String, Object> multipartMap = new LinkedMultiValueMap<>();
multipartMap.add("atom", atomPart);
multipartMap.add("file", filePart);

// 设置请求头:指定multipart/related类型和主类型(type=application/atom+xml)
HttpHeaders requestHeaders = new HttpHeaders();
// 如果你需要手动指定boundary,可以这样写
requestHeaders.setContentType(MediaType.parseMediaType("multipart/related;boundary===9B752C681081408==;type=application/atom+xml"));
// 不需要手动指定boundary的话,用下面的方式,RestTemplate会自动生成合适的boundary
// requestHeaders.setContentType(new MediaType("multipart", "related", Collections.singletonMap("type", "application/atom+xml")));

HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multipartMap, requestHeaders);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);

备选方案:使用WebClient实现(更简洁)

如果你可以切换到WebClient,代码会更直观,不需要手动配置太多转换器:

WebClient webClient = WebClient.create();

Mono<String> responseMono = webClient.post()
    .uri(url)
    .contentType(MediaType.parseMediaType("multipart/related;type=application/atom+xml"))
    .body(BodyInserters.fromMultipartData(
        MultipartBodyBuilder.create()
            .part("atom", e)
                .contentType(new MediaType("application", "atom+xml"))
            .part("file", new FileSystemResource(file))
                .contentType(MediaType.parseMediaType("video/mp2t"))
                .header("Content-ID", "<prod@example.com>")
            .build()
    ))
    .retrieve()
    .bodyToMono(String.class);

// 同步获取结果(如果需要非异步的话)
String responseBody = responseMono.block();

关键要点总结

  • 每个multipart部件必须包装成HttpEntity(RestTemplate)或通过MultipartBodyBuilder配置(WebClient),才能自定义头部。
  • 确保消息转换器支持对应的媒体类型,否则会出现序列化/反序列化错误或头部不匹配的问题。
  • 请求的Content-Type必须明确设置为multipart/related,并通过type参数指定主部件的媒体类型(这里是application/atom+xml)。

内容的提问来源于stack exchange,提问作者Dawid Sobierajski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 06:42:55