Spring Boot RestTemplate服务间字节数组传输配置与反序列化问题
业务场景
从Kafka主题消费消息后,通过RestTemplate将消息转发至独立下游服务。考虑到消息类型不固定,计划将消息载荷转为字节数组传输,由下游服务自行将收到的字节数组反序列化为对应业务格式。
开发遇到的问题
- 通过RestTemplate发送字节数组时,应设置哪种Content-Type?
- 已尝试使用
application/octet-stream作为内容类型发送,但下游服务收到字节数组后,无法将其还原为测试使用的XML格式字符串。
相关示例代码
KafkaTopicListener.java
@KafkaListener(topics = "test-topic", groupId = "group-id", containerFactory = "kafkaListenerContainerFactory") public void listen(ConsumerRecord<String, byte[]> cr, @Payload byte[] payload) { System.out.println("KafkaTopicListener.listen : payload :: " + payload.toString()); String s = new String(payload); System.out.println("KafkaTopicListener.listen : payload :: " + s); // 消费端读取正常:测试时自行投递到Kafka的XML格式字符串,可直接通过new String()还原 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM)); HttpEntity<Object> entity = new HttpEntity<>(payload, headers); restTemplate.postForLocation(nextSerivceURL, entity); }
NextServiceController.java
@RequestMapping(value = "/testByteArray", method = RequestMethod.POST) public void testByteArray(@RequestBody byte[] payload) throws IOException, ClassNotFoundException { // String s = new String(payload); // System.out.println("NextServiceController.testByteArray::" + decoded.toString()); String s = new String(payload); System.out.println("NextServiceController.testByteArray String::" + s); // 下游打印结果仅能得到Base64编码字符串,无法还原为原始XML格式: // NextServiceController.testByteArray String::"ICAgIDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04Ij8+DQogICAgPGx2Yl9zeXN0ZW0geG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNja//GVtYS1pbnN0YW5jZSIgeHNpOm5vTmFtZXNwYWNlU2NoZW1hTG9jYXRpb249InNhbXBsZS54c2QiPg0KICAgIDxsaW5lIGlkPSIxIj4NCiAgICANCiAgICAgICAgPHR5cGU+dHlwZTwvdHl//wZT4NCiAgICAgICAgPHN0YXJ0X3RpbWVfb3BlcmF0aW9uPjEyOjA6MDA8L3N0YXJ0X3RpbWVfb3BlcmF0aW9uPg0KICAgICAgICA8ZW5kX3RpbWVfb3BlcmF0aW9uPjEyOjAwOjAwPC9lb//mRfdGltZV9vcGVyYXRpb24+DQogICAgICAgIDxjb3VudF92ZWhpY2xlcz4wPC9jb3VudF92ZWhpY2xlcz4NCiAgICAgICAgPG1hcD5tYXA8L21hcD4NCiAgICAgICAgPHN0YXJ0X3N0YXR//pb24gaWQ9IjEiPg0KICAgICAgICA8bmFtZT5uYW1lPC9uYW1lPg0KICAgICAgICA8L3N0YXJ0X3N0YXRpb24+DQogICAgICAgIDxlbmRfc3RhdGlvbiBpZD0iMSI+DQogICAgICAgIDxuY//W1lPm5hbWU8L25hbWU+DQogICAgICAgIDwvZW5kX3N0YXRpb24+DQogICAgICAgIDxpbnRlcm1lZGlhdGVfc3RhdGlvbnMgaWQ9IjEiPg0KICAgICAgICA8bmFtZT5uYW1lPC9uYW1lPg0//KICAgICAgICA8L2ludGVybWVkaWF0ZV9zdGF0aW9ucz4NCiAgICAgICAgPHZlaGljbGVzX2xpbmUgaWQ9IjEiPg0KICAgICAgICA8bmFtZT5uYW1lPC9uYW1lPg0KICAgICAgICA8Y2FwY//WNpdHk+MDwvY2FwYWNpdHk+DQogICAgICAgIDwvdmVoaWNsZXNfbGluZT4NCiAgICA8L2xpbmU+DQogICAgPC9sdmJfc3lzdGVtPg0K" }
问题解答与修复方案
Content-Type选择
传输任意无固定格式的字节数组,标准Content-Type即为application/octet-stream,该设置本身符合规范,无需调整。
下游无法还原原始XML的根因
出现Base64编码字符串的核心原因是RestTemplate的消息转换器匹配优先级问题:
- Spring Boot自动配置RestTemplate时,会优先注册
MappingJackson2HttpMessageConverter,该转换器默认会把byte[]类型的对象序列化为Base64格式的字符串写入请求体。 - 因为Jackson转换器的优先级高于
ByteArrayHttpMessageConverter,你的字节数组在发送时没有被直接以原始字节写出,反而被Jackson转成了Base64文本,最终下游收到的是Base64文本的字节内容,自然无法通过new String()还原成原始XML。
具体修复步骤
- 调整RestTemplate的消息转换器顺序,将
ByteArrayHttpMessageConverter的优先级提到Jackson转换器之前,确保当请求体类型为byte[]、Content-Type为application/octet-stream时,直接写出原始字节,不做转码。 - 移除手动设置的
Accept: application/octet-stream请求头,避免不必要的转换器匹配逻辑。 - 下游服务无需修改配置,Spring MVC默认注册的
ByteArrayHttpMessageConverter可正确读取原始请求体字节,只要上游发送的是原始字节流,下游即可通过new String()正确还原为原始XML格式。
内容的提问来源于stack exchange,提问作者Reese
相关产品推荐
相关产品推荐

