Postman多部分文件数据编码问题及Java请求适配咨询
问题根源与解决方案
首先得明确:你看到Postman里的PDF内容并不是什么编码后的字符串,而是原始二进制字节的可视化展示——Postman发送附件时,是直接把文件的原始二进制字节放到multipart请求的对应part里,根本没有做字符编码转换。你手动用字符串读取二进制文件的做法,从一开始就破坏了文件的原始字节结构,这才是附件损坏的核心原因。
为什么你的代码会出问题
不管你用UTF-8、ISO_8859_1还是其他编码,FileUtils.readFileToString都是把二进制字节序列尝试转换成字符序列,再把字符序列转成字节序列写入请求。但二进制文件(比如PDF、图片)的字节流并不是合法的字符编码序列,转换过程中必然会丢失或篡改原始字节,导致文件损坏。
正确的做法:用Spring的Multipart工具类构造请求
Spring的RestTemplate本身就支持构造multipart请求,完全不需要手动拼接字符串。直接用MultipartBodyBuilder来构建各个form part,包括文本字段和二进制附件,Spring会自动处理multipart的边界、Content-Type等细节,也会正确传输文件的原始字节。
修改后的代码示例:
class SendMailAdaptorImpl implements SendMailAdaptor { private static final String PART_DELIMITER = "Eh0oKOHPOSEIJTzFevDxHhPNKhQl7AP6kQL"; private final String channelId = "..."; private final String endpoint = "..."; private final RestTemplate restTemplate = new RestTemplate(); @Override public APIMailResponse sendMail(String from, String to, String templateId, List<String> templateParameters, File attachment) { // 使用MultipartBodyBuilder构建请求体 MultipartBodyBuilder builder = MultipartBodyBuilder.create(); // 添加文本字段 builder.part("to", to); builder.part("from", from); builder.part("template_id", templateId); builder.part("channel_id", this.channelId); builder.part("template_parameter", constructTemplateParameter(templateParameters)); // 添加附件(如果存在) if (attachment != null) { // 用FileSystemResource包装文件,Spring会自动处理二进制传输 FileSystemResource resource = new FileSystemResource(attachment); builder.part("attach_file_content", resource) .header("Content-Disposition", "form-data; name=\"attach_file_content\"; filename=\"" + attachment.getName() + "\"") .header("Content-Type", guessAttachmentMimeType(attachment)); builder.part("attach_file_name", attachment.getName()); } // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA.withParameter("boundary", PART_DELIMITER)); // 构造请求实体 HttpEntity<MultiValueMap<String, HttpEntity<?>>> request = new HttpEntity<>(builder.build(), headers); URI uri = UriComponentsBuilder.fromHttpUrl(endpoint) .build().encode(StandardCharsets.UTF_8).toUri(); return restTemplate.postForObject(uri, request, APIMailResponse.class); } private String guessAttachmentMimeType(File attachment) { try { return Files.probeContentType(attachment.toPath()); } catch (IOException e) { throw new UncheckedIOException(e); } } private String constructTemplateParameter(List<String> templateParameters) { return templateParameters.stream().reduce("Name", (a, b) -> a + "|" + b); } }
关键说明
- 二进制文件必须以字节流的形式传输,绝对不能转换成字符串处理——字符串是用来处理文本数据的,不是二进制数据。
- 不存在“硬编码某个编码适配各类文件”的可能,因为二进制文件本身没有字符编码的概念,只有文本文件才需要考虑编码。
- 用Spring提供的multipart工具类,不仅能避免手动拼接的错误,还能自动处理边界冲突、编码等细节,比手动构造字符串可靠得多。
内容的提问来源于stack exchange,提问作者asinkxcoswt
相关产品推荐
相关产品推荐

