房产局网站建设方案,wordpress响应式网站模板,2017网站设计,网页区设计网站诊断1 前言 
最近在开发中遇到文件上传采用Base64的方式上传#xff0c;记得以前刚开始学http上传文件的时候#xff0c;都是通过content-type为multipart/form-data方式直接上传二进制文件#xff0c;我们知道都通过网络传输最终只能传输二进制流#xff0c;所以毫无疑问他们本…1 前言 
最近在开发中遇到文件上传采用Base64的方式上传记得以前刚开始学http上传文件的时候都是通过content-type为multipart/form-data方式直接上传二进制文件我们知道都通过网络传输最终只能传输二进制流所以毫无疑问他们本质上都是一样的那么为什么还要先转成Base64呢这两种方式有什么区别带着这样的疑问我们一起来分析下。 
2 multipart/form-data上传 
先来看看multipart/form-data的方式我在本地通过一个简单的例子来查看http multipart/form-data方式的文件上传html代码如下 html 
复制代码 
!DOCTYPE html html head title上传文件示例/title meta charsetUTF-8 body h1上传文件示例/h1 form action/upload methodPOST enctypemultipart/form-data label forfile选择文件/label input typefile idfile namefilebr label fortx说明/label input typetext idtx nameremarkbrbr input typesubmit value上传 /form /body /html  
页面展示也比较简单 选择文件点击上传后通过edge浏览器f12进入调试模式查看到的请求信息。 请求头如下 在请求头里Content-Type 为 multipart/form-data; boundary----WebKitFormBoundary4TaNXEII3UbH8VKo刚开始看肯定有点懵不过其实也不复杂可以简单理解为在请求体里要传递的参数被分为多部份每一部分通过分解符boundary分割就比如在这个例子表单里有file和remark两个字段则在请求体里就被分为两部分每一部分通过boundary----WebKitFormBoundary4TaNXEII3UbH8VKo来分隔实际上还要加上CRLF回车换行符回车表示将光标移动到当前行的开头换行表示一行文本的结束也就是新文本行的开始。需要注意下当最后一部分结尾时需要加多两个-结尾。 我们继续来看请求体 第一部分是file字段部分它的Content-Type为image/png第二部分为remark字段部分它没有声明Content-Type则默认为text/plain纯文本类型也就是在例子中输入的“测试”到这里大家肯定会有个疑问上传的图片是放在哪里的这里怎么没看到呢别急我猜测是浏览器做了特殊处理请求体里不显示二进制流我们通过Filder抓包工具来验证下。 可以看到在第一部分有一串乱码显示这是因为图片是二进制文件显示成文本格式自然就乱码了这也证实了二进制文件也是放在请求体里。后端使用框架springboot通过MultipartFile接受文件也是解析请求体的每一部分最终拿到二进制流。 java 
复制代码 
RestController public class FileController { // RequestParam可接收Content-Type 类型为multipart/form-data  // 或 application/x-www-form-urlencoded 请求体的内容 PostMapping(/upload) public String upload(RequestParam(file) MultipartFile file) { return test; } }  
到此multipart/form-data方式上传文件就分析完了关于multipart/form-data官方说明可参考 RFC 7578 - Returning Values from Forms: multipart/form-data (ietf.org) 
3 Base64上传 
在http的请求方式中文件上传只能通过multipart/form-data的方式上传这样一来就会有比较大的限制那有没其他方式可以突破这一限制也就是说我可以通过其他的请求方式上传比如application/json当然有把文件当成一个字符串和其他普通参数没什么两样我们可以通过其他任意请求方式上传。如果转成了字符串那上传文件就比较简单了但问题是我们怎么把二进制流转成字符串因为这里面可能会有很多“坑”业界一般的做法是通过Base64编码把二进制流转成字符串那为什么不直接转成字符串而要先通过Base64来转呢我们下面来分析下。 
3.1 Base64编码原理 
在分析原理之前我们先来回答什么是Base64编码首先我们要知道Base64只是一种编码方式并不是加解密算法因此Base64可以编码那也可以解码它只是按照某种编码规则把一些不可显示字符转成可显示字符。这种规则的原理是把要编码字符的二进制数每6位分为一组每一组二进制数可对应Base64编码的可打印字符因为一个字符要用一个字节显示那么每一组6位Base64编码都要在前面补充两个0因此总长度比编码前多了(2/6)  1/3因为6和8最小公倍数是24所以要编码成Base64对字节数的要求是3的倍数24/83字节对于不足字节的需要在后面补充字节数补充多少个字节就用多少个表示一个或两个这么说有点抽象我们通过下面的例子来说明。 我们对ASCII码字符串AB\nC(\n和LF都代表换行)进行Base64编码因为一共4字节为了满足是3的倍数需要扩展到6个字节后面补充了2个字节。 表3.1 
转成二级制后每6位一组对应不同颜色每6位前面补充两个0组成一个字节最终Base64编码字符是QUIKQwBase64编码表大家可以自行网上搜索查看。 我们通过运行程序来验证下 最终得出的结果与我们上面推理的一样。 
3.2 Base64编码的作用 
在聊完原理之后我们继续来探讨文件上传为什么要先通过Base64编码转成字符串而不直接转成字符串一些系统对特殊的字符可能存在限制或者说会被当做特殊含义来处理直接转成普通字符串可能会失真因此上传文件要先转成Base64编码字符不能把二进制流直接字符串。 
另外相比较multipart/form-data Base64编码文件上传比较灵活它不受请求类型的限制可以是任何请求类型因为最终就是一串字符串相当于请求的一个参数字段它不像二进制流只能限定multipart/form-data的请求方式日常开发中我们用的比较多的是通过apllication/json的格式把文件字段放到请求体这种方式提供了比较便利的可操作性。 
4 总结 
本文最后再来总结对比下这两种文件上传的方式优缺点。 1multipart/form-data可以传输二进制流效率较高Base64需要编码解码会耗费一定的性能效率较低。 2Base64不受请求方式的限制灵活度高http文件二进制流方式传输只能通过multipart/form-data的方式灵活度低。 因为随着机器性能的提升小文件通过二进制流传输和字符串传输我们对这两种方式时间延迟的感知差异并不那么明显因此大部分情况下我们更多考虑的是灵活性所以采用Base64编码的情况也就比较多。