前后端对接时,后端常有返回二进制流文件的情况,前端需要下载或预览(pdf、html、图片文件等)。下面介绍几种实现前端获取二进制流并下载或预览的方式

1.直接预览二进制流文件

如果返回的二进制流是一个pdf文件或图片文件。那么可以通过打开新标签页的方式进行文件预览。例如请求如下接口https://via.placeholder.com/150/24f355,返回一个图片文件,前端可以使用window.open("https://via.placeholder.com/150/24f355")来打开新标签页实现预览。
当然这种情况是接口并没有做其他处理,如果接口需要验证token请求头使用window.open是无法设置请求头的。下面会介绍如何解决需要token的情况

2.使用Blob对象实现下载

使用Blob对象实现下载主要分为以下几步:

  1. 设置接口请求的responseType值为'Blob'
  2. 创建Blob对象const blob = new Blob([data])
  3. 创建一个不显示的a标签,点击下载按钮时实际跳转a标签的地址,完成下载
const link = document.createElement('a')     // 创建a标签
link.download = '文件名称.后缀名'              // 设置下载的文件名称
link.style.display = 'none'
link.href = window.URL.createObjectURL(blob) // 创建Blob对象的URL赋值给a标签
link.target = 'blank'
document.body.append(link)					 // 将a标签添加到页面中
link.click()								 // 点击a标签实现下载
  1. 释放URL对象
window.URL.revokeObjectURL(link.href)
document.body.removeChild(link)

下面就是一个具体的例子

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>blob下载文件</title>
</head>

<body>
  <button id="blobDown">下载</button>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

  <script type="text/javascript">
    document.getElementById("blobDown").onclick = function () {
      axios.get('https://img1.baidu.com/it/u=2921118138,3990044703&fm=26&fmt=auto', {
        responseType: 'blob',
      }).then(res => {
        console.log(res.data);
        const blob = new Blob([res.data])
        const link = document.createElement('a')
        link.download = '王冰冰.jpg'
        link.style.display = 'none'
        link.href = window.URL.createObjectURL(blob)
        link.target = 'blank'
        document.body.append(link)
        link.click()
      })
    }
  </script>
</body>

</html>

3.对blob下载二进制文件流的方法进行抽离

/**
 *
 * @param {*} data blod文件流
 * @param {*} fileName 下载后的文件名称
 */
function downloadBlob(data, fileName) {
  const blob = new Blob([data])
  if ('download' in document.createElement('a')) {
    // 非IE下载
    const elink = document.createElement('a')
    elink.download = fileName
    elink.style.display = 'none'
    elink.href = URL.createObjectURL(blob)
    elink.target = 'blank'
    document.body.appendChild(elink)
    elink.click()
    URL.revokeObjectURL(elink.href) // 释放URL 对象
    document.body.removeChild(elink)
  } else {
    // IE10+下载
    navigator.msSaveBlob(blob, fileName)
  }
}

4. 解决window.open无法预览需要请求头的接口返回的二进制流

实际开发中,后端的接口都会需要用户验证,通常是放在请求头某个参数或具体的请求参数中。
如果在请求头中,那么window.open预览文件流则无法配置请求头,这时可以用blob解决

axios.get('https://img1.baidu.com/it/u=2921118138,3990044703&fm=26&fmt=auto', {
  	responseType: 'blob',
  	headers: {'Authorization': 'tokenInfo'} // 这里设置对应的请求头
 }).then(res => {
   	console.log(res.data);
   	// 创建Blob对象的时候,设置指定的文件格式。如果是pdf则设置 'type: "application/pdf"'
   	const blob = new Blob([res.data], {type: 'image/jpeg'})  
   	const link = document.createElement('a')
   	link.href = window.URL.createObjectURL(blob)
  	link.target = 'blank'
   	link.click()
 })