前言
最近集中遇到了HTTP相关方面的问题,意识到自己的HTTP协议一些细节点掌握的还不够,而前端实现下载是日常中非常常见的点,从下载为起点引发了一系列的思考。
思考的问题如下:
- 为什么不能直接使用Ajax实现下载?
前后端接口传参,参数类型是什么?
而本文也会围绕这两个问题进行探讨。
具体分析
为什么不能使用Ajax直接实现下载?
场景
业务要求实现导出文件功能,后台给了一个二进制流形式下载的Get类型接口
你想:使用项目中ajax库来发送给Get请求,应该就可以了吧
你“键步”如飞,敲下一行get请求代码,发现没有效果
你Google了一下,发现使用a标签可以实现,就使用a标签+download来实现了下载。
但是为什么呢?这个想法一直缠绕着你。
疑问
a标签就是发送一个Get请求,使用Ajax也是发送个Get请求,一个可以实现下载,一个不可以,差异就是二者的区别了。
在网上你找到了答案:
a标签+download会触发浏览器的下载机制
那是不是可以这么认为Ajax不会触发浏览器的下载机制呢?实际上就是如此。
Ajax就是使用XMLHttpRequest对象实现的:
var xhr = new XMLHttpRequest();
xhr.open(method,url);
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
}
};
xhr.send(data);
请求成功之后,你要获取请求到的数据:
response、responseText、responseXML
responseText实际上就是文本,即DOMString类型
responseXML实际是处理html/xml的Document类型
response实际上是包含所有类型的结果即responseType的类型,具体的类型有:
值 | 数据类型 |
---|---|
‘’ | DOMString(文本类型) |
arraybuffer | ArrayBuffer(二进制数组) |
blob | Blob(二进制流) |
document | Document(文档html/xml等) |
json | JSON可以通过JS的parse转换成js对象 |
text | DOMString(文本类型) |
通过response你可以获取服务器端传递的各种形式的数据
实际上responseType与Http中Content-type对应,不过是一对多的关系,例如:
Document可与text/html、text/xml等MIME对应
就上面的场景:
Ajax获取到二进制流内容之后,其不会自动触发浏览器的下载机制,这就是不能直接使用ajax下载的原因
总结
可以实现下载的方式:
- 使用saveAs浏览器命令来实现下载
- 使用a标签 + download 或 a标签 + download + URL.createObjectUrl()
- 使用window.open + URL.createObjectUrl() 或 FileReader
- 使用location.href + URL.createObjectUrl() 或 FileReader
- 使用Form表单来实现下载
- 使用iframe来实现下载
- 使用ajax + FormData来模拟表单提交
实际上前4种正是FileSaver源码的实现方式,具体可看之前FileSaver源码分析这篇文章。
前后端接口传参,参数类型是什么?
场景
后台接口要求number类型的时间戳,而传递到后台的类型到底是什么
实际上上面的场景正是HTTP本质的体现
HTTP是基于ASCII的即请求行和首部字段都是ASCII流传输的,而实体部分是字节流传输
物理底层都是比特流,在HTTP中传输,数据都是字符串即JS中数组、Number、Boolean类型在到达服务器上应用程序都是文本,传递到服务器上的参数类型都是文本,不存在什么类型,具体的类型实际上服务器应用程序处理决定的。
Content-type指定实体部分内容类型或字符编码,服务器端根据这里来处理转换实体内容。
总结
实际上上面这两个问题,涉及到的知识点相当多例如HTTP、字符集、解码、编码等等,只是简单的从表象谈了谈,希望之后能够更加深入研究研究。