资源的响应是如何触发浏览器下载行为的

639 阅读2分钟

问题:对于服务端响应的数据为二进制文件(图片、视频、音频、zip...)或者是纯文本,浏览器如何判断是应该为用户展示资源还是download它?

这里的处理和两个HTTP响应头——content-dispositioncontent-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-dispositioncontent-type来决定对资源做展示还是download处理:

  1. content-dispositionattachment,则对该资源做下载处理;

  2. content-dispositioninline(默认)时,浏览器会根据content-type类型不同来做对应处理:

    • content-typeapplication/jsontext/htmltext/cssimage/jpeg等浏览器可以识别的资源类型,浏览器对资源做展示处理
    • content-typeapplication/octet-streamapplication/zip等浏览器认为无法处理的资源类型,浏览器也会做下载处理

在实际的项目开发中,比如遇到导出订单列表为excel保存到用户本地的需求时,只需要服务端在响应的文件流头部设置即可:

content-disposition: attachment;filename=****.xls

以上策略是在浏览器导航栏输入资源url的场景下作用的,前端可以通过以对应资源地址为内容去新开浏览器窗口(window.open()),利用浏览器的资源处理策略触发浏览器的下载行为。

但有些场景服务端提供的接口是需要POST方法请求的,如果想触发浏览器的下载行为,与GET接口有所区别:

  1. 对于支持GET方法请求的资源,服务端设置好响应头content-disposition: attachment后,前端通过JavaScript新开浏览器窗口即可实现download;
  2. 对于其他方法如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请求的场景。