为什么在将byte数组转换成JSON时,Jackson会将其转换为Base64字符串?

3

当我在 DTO 中有一个字节数组并使用 Jackson 的 ObjectMapper 将其转换为 JSON 时,它会自动将字节数组转换为 Base64 字符串。以下是示例。

@Data
@AllArgsConstructor
class TestDTO {
    private byte[] binaryFile;
}

class TestByteSerialization {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = Files.readAllBytes(new File("path/to/file/test.pdf").toPath());

        TestDTO dto = new TestDTO(bytes);

        String json = objectMapper.writeValueAsString(dto);
        System.out.println(json);
    }
}

我期望jackson能将其转换为以下的整数数组:
{
    "binaryFile" : [21, 45, 12, 65, 12 ,37, etc]    
}

但事实上,我发现它被转换为base64字符串了。

{
    "binaryFile" : "ZXhhbXBsZSB0ZXh0IG9ubHkuIEJpbmFyeSBmaWxlIHdhcyBkaWZmZXJlbnQgTE9MLg=="    
}

经过一番研究,似乎json不支持字节数组,如此所述。这是有道理的,因为json是数据的字符串表示形式。
但我仍然找不到答案:为什么json不支持字节数组?它仍然只是一个数字数组,将其作为一个数字数组传递给json字符串需要转换成base64编码的字符串吗?直接将字节数组传递给json字符串有何问题?
对于那些认为这是基于观点的问题的人:
开发人员肯定不会想到“将字节作为数字数组传递很无聊,让我们尝试一些看起来很疯狂的编码字符串”。这肯定有一些合理的原因。

2
可能有很多原因,但我能想到的一个是大小。作为一个数字,每个字节需要1-3个字符+逗号,当反序列化它时,Jackson至少需要为每个int使用4个字节,直到它们可以转换为一个字节数组。因此,你需要2-4倍的内存,而使用Base64只需要大约1.33倍的内存。 - Thomas
1
我认为寻求技术解释以理解事物为何以特定方式工作并不是基于观点的问题。 - Arun Gowda
JSON很好地支持了字节数组(好吧,严格来说是整数数组),因此前提是错误的;通常不建议以这种方式发送字节数组。 - Mark Rotteveel
快点,各位。正如我在编辑中所解释的那样,这不是一个基于观点的问题。请投票重新开放相同的问题。 - Arun Gowda
1个回答

17
将字节数组直接传递给json字符串作为数字数组有什么问题吗?
如果您满意每个输入字节需要(平均情况下,假设字节均匀分布)3.57个字符,则没有任何问题。这是假设每个逗号后面都没有空格的情况下计算的,否则它将为4.57个字符。
那么请将这些数据大小与10K数据进行比较:
- 原始数据:10240字节(无法直接表示为JSON) - Base64编码:13656个字符 - 数字数组:36556个字符
Base64编码的33%的大小增加已经很痛苦了...使用数组的大小增加则更加严重。因此,使用约定而不是直接使用数字数组。 (这只是一个约定-它不像嵌入到JSON规范中那样。但它被大多数JSON编码器和解码器遵循。)

对于传输单个二进制文件,有什么理由可以优先选择json而不是将字节资源作为“application/octet-stream”发送吗? - Arun Gowda
2
@ArunGowda:那是一个完全不同的问题 - 非常不适合在Stack Overflow评论中讨论。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接