为什么字节数组在 Java 中通过 rest 模板传输时变成字符串

Why byte array becomes string while transferring it via rest template in Java

这是两个SpringBoot项目。 A 为 api 提供服务,B 通过 rest 模板消费 A 的服务。传输字符串时可以。通过字节数组传输 Excel 文件时,B 收到一个字符串,而不是字节数组。

A中的api方法

@GetMapping(value = "/export")
@ResponseBody
public HSResult exportFile(@RequestParam(value = "fileName", defaultValue = "-1") String fileName,
                           @RequestParam(value = "provider", defaultValue = "-1") String channelId,
                           @RequestParam(value = "fileStatus", defaultValue = "-5") int fileStatus,
                           @RequestParam(value = "cdate", defaultValue = "") String cdate,
                           HttpServletRequest request, HttpServletResponse response) {

  // ...... some logic code
  InputStream inputStream=new FileInputStream(fullPath);
  long fileSize=new File(fullPath).length();
  byte[] allBytes = new byte[(int) fileSize];
  inputStream.read(allBytes);
  result = HSResult.build(200, "exportFile success",allBytes);
  return result;
}

B中的消费方法

public ResponseEntity downLoadFile(int businessType, String fileName, int fileStatus, HttpServletResponse response) {

    //.......

    ResponseEntity<HSResult> responseEntity = restTemplate.getForEntity(url, HSResult.class);
    HSResult apiResult = responseEntity.getBody();
    byte[] fileData = (byte[]) apiResult.getData();

    //.......

}

A 在传输之前将 excel 文件从磁盘读取到字节数组中。

但是在B端接收到的结果是UEsDBC0AAAAIADhMuVAKVjbC/////////8LABQAX3Jl这样的字符串

为什么会这样?以及如何通过 rest 模板正确传输字节数组?谢谢。

PS: HSResult

的class
public class HSResult {

  private Integer status;
  private String msg;
  private Object data;

  //gets and setters    
  //......

}

终于找到了根本原因。与可能遇到相同问题的人分享。

  1. A端在HSResultdata字段中放入了一个字节数组,该字段是object类型。
  2. 在 B 端接收此信息时,其余模板正试图将所有数据转换回 HSResult。对于字节数组,接收字段 data 是对象类型。所以 rest 模板不知道它是什么具体类型,然后将字节数组转换为字符串,并进行一些解码。不知道是UTF8还是GB2312还是别的。

如何解决?只需指定特定类型的接收字段,而不是对象。

public class HSResult {

    private Integer status;
    private String msg;
    private byte[] data;

    //gets and setters  

}

那就一切OK了

感谢 Ken 的提醒。 http是文本协议,不能直接传输byte数组,所以必须先把byte数组转成string。

我已经使用 Gson() class 将对象转换为 json!字节数组也没有问题。

当我想将我的代码移动到 spring 时遇到这个问题,所以我通过序列化 byte[] filed:

解决了这个问题
class ByteArraySerializer: JsonSerializer<ByteArray>() {

    override fun serialize(bytes: ByteArray, jsonGenerator: JsonGenerator, serializerProvider: SerializerProvider?) {
        val intArray = intArray(bytes)
        jsonGenerator.writeArray(intArray, 0, intArray.size)
    }

    private fun intArray(input: ByteArray): IntArray {
        val ret = IntArray(input.size)
        for (i in input.indices) ret[i] = input[i].toInt() // & 0xff -> 0-255
        return ret
    }
}

convert byte array to int array

然后在我的 class:

中使用它
data class VideoInfo(val durationMS: Int = 0): Serializable {

    @JsonSerialize(using = ByteArraySerializer::class)
    var bytes: ByteArray? = null
}

它将return json对象如下:

{
  "bytes": [-1,-40, ..., 0],
  "durationMS": 8870
}

它是 kotlin,你可以轻松地将它转换为 java :)