问题:对于服务端响应的数据为二进制文件(图片、视频、音频、zip...)或者是纯文本,浏览器如何判断是应该为用户展示资源还是download它?
这里的处理和两个HTTP响应头——content-disposition和content-type有关。
1. content-disposition
HTTP响应头部中的content-disposition字段用来告知客户端响应的内容应该以何种形式处理,有两种取值:
inline,默认值,告知浏览器在窗口内尝试展示资源attachment,告知浏览器下载资源
那么,如果希望浏览器展示该资源,只需要响应content-disposition: inline就够了呢?也不是,上文说过了,浏览器会尝试在窗口中展示content-disposition: inline的资源,但浏览器又怎么知道该以何种形式展示那些资源的呢?接着往下看。
2. content-type
HTTP响应头部中的content-type字段用来告知客户端实际返回的内容的MIME类型(更多MIME类型列表):
常见的content-type值有:
- application/json
- application/octet-stream
- application/pdf
- application/zip
- font/woff
- text/css
- text/plain
- text/html
- text/javascript
- image/gif
- image/jpeg
浏览器会根据资源的响应头content-disposition、content-type来决定对资源做展示还是download处理:
-
当
content-disposition是attachment,则对该资源做下载处理; -
当
content-disposition是inline(默认)时,浏览器会根据content-type类型不同来做对应处理:- 当
content-type为application/json、text/html、text/css、image/jpeg等浏览器可以识别的资源类型,浏览器对资源做展示处理 - 当
content-type为application/octet-stream、application/zip等浏览器认为无法处理的资源类型,浏览器也会做下载处理
- 当
在实际的项目开发中,比如遇到导出订单列表为excel保存到用户本地的需求时,只需要服务端在响应的文件流头部设置即可:
content-disposition: attachment;filename=****.xls
以上策略是在浏览器导航栏输入资源url的场景下作用的,前端可以通过以对应资源地址为内容去新开浏览器窗口(window.open()),利用浏览器的资源处理策略触发浏览器的下载行为。
但有些场景服务端提供的接口是需要POST方法请求的,如果想触发浏览器的下载行为,与GET接口有所区别:
- 对于支持GET方法请求的资源,服务端设置好响应头
content-disposition: attachment后,前端通过JavaScript新开浏览器窗口即可实现download; - 对于其他方法如POST请求的资源,前端通过ajax请求资源,将http响应体处理为blob对象结合HTML5 a元素的download属性下载:
request
.post('*****')
.then(res => res.blob())
.then(res => {
const blobUrl = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.download = downloadName
a.href = blobUrl
a.click()
})
当然, 第二种方式同样适用于GET请求的场景。