通过a标签同源和跨域下载服务器文件

同源下载(推荐)

  • 优点是:通过浏览器的默认行为下载,不会阻塞
  • 缺点是:必须是同源下载,不过现在都是 webpack 和 nignx 代理,所以推荐这种下载方式
  • 简单说说:如果响应头添加 Content-Disposition,可不使用 download,两者都可以阻止浏览器默认打开文件,而不是下载文件的行为,但是前者优先级比后者高
/**
 * @description: 从远程url下载文件(同源)
 * @param {string} url -远程的url和参数
 * @param {string} filename -下载到本地的文件名
 */
export const downLoadFile = (url: string, filename: string) => {
  const origin = `/api/${url}`
  const aLink = document.createElement("a")
  aLink.style.display = "none"
  aLink.href = origin
  aLink.download = filename
  aLink.target = "_black"
  aLink.type = "application/octet-stream" // 让浏览器知道是二进制
  document.body.appendChild(aLink) // 如果不挂载到body上,火狐浏览器会失效
  aLink.click()
  document.body.removeChild(aLink)
}

跨域下载

  • 缺点是:要等 blob 封装完成才能下载,如果想实现前端流式下载,可参考fetch 方法
  • 优点是:可以携带 Cookie 和请求体 实现动态下载
/**
 * @description: 获取 blob
 * @param {string} url -目标文件地址
 */
function getBlob(url: string) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest()
    xhr.open("GET", url, true)
    xhr.responseType = "blob"
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.response)
      }
    }
    xhr.send()
  })
}
/**
 * @description: 下载blob工具函数
 * @param {string} blob -文件流
 * @param {string} filename -下载的文件名
 */
function saveAs(blob: Blob, filename: string) {
  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)
  }
}
/**
 * @description: 用户调用的下载函数
 * @param {string} url -目标文件地址(跨域)
 * @param {string} newFilename -想要保存的文件名称
 */
export async function download(url: string, newFilename: string) {
  const blob: Blob = await getBlob(url)
  saveAs(blob, newFilename)
}

参考

Published under  on .

Last updated on .

pipihua

我是皮皮花,一个前后端通吃的前端攻城狮,如果感觉不错欢迎点击小心心♥(ˆ◡ˆԅ) star on GitHub!