前端通过url下载文件时进行重命名(fileSaver部分源码解析)

谈到文件下载,相信绝大多数的人都会想到a标签

比如,W3school的一个基础案例

<a href="/images/myw3schoolimage.jpg" download="w3logo">

我们可以用download来修改下载的文件名

然而一切并不是那么简单

1.跨域的时候利用download去修改文件名并不生效
2.当href指向为图片的时候,并不会下载图片,而是执行了预览图片

github上有现有的资源可以使用 fileSaver.js

其实逻辑非常简单,提取了这一小部分代码

/**
 * 获取 blob
 * @param  {String} url 目标文件地址
 * @return {Promise}
 */
function getBlob(url) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest()
    // 避免 200 from disk cache
    url = url + `?r=${Math.random()}`
    xhr.open('GET', url, true)
    xhr.responseType = 'blob'
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.response)
      }
    }
    xhr.send()
  })
}

/**
 * 保存
 * @param  {Blob} blob
 * @param  {String} filename 想要保存的文件名称
 */
function saveAs(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename)
  } else {
    const anchor = document.createElement('a')
    const body = document.querySelector('body')
    anchor.href = window.URL.createObjectURL(blob)
    anchor.download = filename

    anchor.style.display = 'none'
    body.appendChild(anchor)

    anchor.click()
    body.removeChild(anchor)

    window.URL.revokeObjectURL(anchor.href)
  }
}

/**
 * 下载
 * @param  {String} url 目标文件地址
 * @param  {String} newFilename 想要保存的文件名称
 */
export async function download(url, newFilename) {
  const blob = await getBlob(url)
  saveAs(blob, newFilename)
}

当我们使用这个简化版的时候,我们必须是对下载的域名可以进行访问的,也就是说我们的xhr对象不会被浏览器的同源策略给影响到。

源码有对服务器端是否允许该域名进行校验,具体代码如下:

if (corsEnabled(blob)) {
  download(blob, name, opts)
} else {
  var a = document.createElement('a')
  a.href = blob
  a.target = '_blank'
  setTimeout(function () {
    click(a)
  })
}

function corsEnabled(url) {
  var xhr = new XMLHttpRequest() // use sync to avoid popup blocker

  xhr.open('HEAD', url, false)
  xhr.send()
  return xhr.status >= 200 && xhr.status <= 299
}

这个可以直接看源码,源码也是非常清晰的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。