数组—当通过resttemplate将文件作为字节[]从java服务发送到java服务时,是否需要额外的base64编码?

7hiiyaii  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(493)

我使用springrestemplate和restcontroller通过post请求中的json主体将数据从客户机(java)发送到服务器(java)。
数据在客户机上以pojo的形式出现,并将被解析为服务器上具有相同结构的pojo。
在客户端上,我正在将一个包含files.readallbytes的文件转换为byte[],并将其存储在content字段中。
在服务器端,包括byte[]在内的整个对象将使用jaxb注解编组为xml。

class BinaryObject {
  String fileName;
  String mimeCode;
  byte[] content;
}

一切正常,运行如期。我听说,在将日期传输到服务器之前对内容字段进行编码,并在将其封送到xml之前对其进行解码,这样做可能是有益的。
我的问题
是否有必要或建议使用base64对内容字段进行额外编码/解码?

ni65a41a

ni65a41a1#

热释光;博士

据我所知,您目前的实施并没有违反任何良好做法。有人可能会质疑这个设计(用json交换文件?在xml中存储二进制文件?),但这是一个单独的问题。
尽管如此,仍然有可能进行优化的空间,但是您使用的工具集(例如spring rest template+spring controler+json序列化(jackson)+xml使用jaxb)对您隐藏了可能的优化。
你必须仔细权衡一下目前工作得很好的舒适的“自动化”序列化的利弊,看看是否值得费心去调整它。
尽管如此,我们还是可以讨论可以做什么的理论。

关于base64的讨论

base64编码以一种高效的方式对纯文本格式的二进制数据进行编码(例如,mime结构,如电子邮件或一些http正文、json、xml等),但它有两个成本:第一个成本是不可忽略的大小增加(~ 33%的大小),第二个成本是cpu时间。
有时,(但您必须分析,检查是否是您的情况),这种成本是不可忽略的,尤其是对于大型文件(由于框架中的一些缓冲和字符/字节转换,您很容易在java堆中使用编码文件大小的4倍)。
当以每秒10个请求的速度处理10kb文件时,这通常不是问题。但是10mb的文件速度是每秒100个请求,这是另一个问题。
所以您必须检查(我怀疑您的典型服务器将达到100req/s和10mb文件,因为这是一个1gb/s的传入网络带宽)。

在您当前的流程中什么是可优化的

在您当前的过程中,发生了多个编码:客户机需要对从文件中读取的字节进行base64编码。
当请求到达服务器时,服务器将base64解码为 byte[] ,然后您的xml序列化(jaxb)重新转换 byte[] 到base64。
所以实际上,“you”(更确切地说,是rest controller端的东西)解码了base64内容,这一切都是徒劳的,因为东西的xml端可以直接使用它。

有什么办法

一些事情。

你在呼叫地点需要base64吗?

首先,您不必在客户端进行编码。当使用json时,别无选择,但是世界并没有等待json通过http交换文件(例如任意二进制内容)。
如果您的内容是一个文件名、一个mime类型和一个文件体,那么完全没有json的标准直接http调用就可以了。
mime类型可以Map到 Content-Type http头,文件中的文件名 Content-Disposition http头,并将内容作为原始http正文。不需要base64(但是需要服务器端按原样接受原始http内容)。这是标准的。
此更改将允许您删除编码(客户端),降低呼叫的网络大小(减少约33%),并删除服务器端的一个解码。服务器只需对一个原始流进行base64编码(一次)就可以生成xml,而且您甚至不需要为此而缓冲整个文件内容(您需要稍微调整一下jaxb模型,但是您可以直接从 InputStream ,这意味着几乎没有缓冲区,而且由于您的cpu编码速度可能快于您的网络服务内容,因此不会产生真正的延迟)。
如果出于某种原因,这不是一个选项,那么假设您的客户机必须发送json(以及base64内容)

你能避免在服务器端解码吗

某种程度上。您可以使用服务器端bean,其中 content 实际上是一个 String 而不是一个 byte[] . 这是黑客攻击,但您的rest控制器将不再反序列化base64,它将保持它“原样”,这是一个json字符串(这恰好是base64编码的内容,但控制器并不在意)。
因此,您的服务器将节省一个base64解码的cpu成本,但作为交换,您将在java堆中拥有一个base64字符串(与原始字符串相比) byte[] ,+33%大小(java>=9,字符串紧凑,+166%大小(java<9))。
如果您要从中获益,还必须调整jaxb以查看base64编码 String 作为一个 byte[] ,就我所知,这并不是微不足道的,除非修改jaxb对象的方式使其接受 String 而不是 byte[] 这是一种黑客行为(如果您的jaxb对象是从xml模式生成的,那么实现起来可能会非常困难)
总而言之,这要困难得多——如果你在这个特定的问题上没有真正做到这一点,就性能而言,可能太难了。

一些其他的东西

你的文件是纯二进制文件,还是真的是文本文件?如果有文本,使用 CDATA 在xml端编码而不是base64?
xml实际上是soap调用吗?如果是这样,并且服务支持mtom,则可以完全避免使用base64,但这是一个完全不同的主题。

相关问题