记录-文件上传和下载-小坑

645 阅读3分钟

记录-文件上传和下载-小坑

  1. 文件下载
    1. 通用封装
  2. 文件上传

1. 文件下载

  1. 针对url(http://xxxxxx/a.zip) 的下载

    • window.open(url, '_self') // 是能下载的链接,就直接下载
    // 以下代码可以控制台直接跑起来
    var data = ['<a id="a"><b id="b">hey!</b></a>']; // data,用数组包裹
    var blob = new Blob(data, {type : 'application/octet-stream;charset=utf-8'}); // 生成Blob对象, Blob对象表示一个不可变、原始数据的类文件对象
    var url = window.URL.createObjectURL(blob) // 生成一个url:可以指向 File 对象或 Blob 对象。
    window.open(url) // 打开url,如果是下载链接则下载
    
  2. 针对文件流的下载

    接口给到一个文件流的话,其实也可以和上面的方法一样去下载。但是缺点是需要用户自己去手动输入 下载的文件名和格式,否则是没有后缀的文件,会显示打不开

    以下我们用dom的download属性下载

    const downFile = (data, filename = '模板.xlsx', headerType = 'application/octet-stream;charset=utf-8') => {
        const blob = new Blob([data], { type: headerType }) // 生成Blob对象, Blob对象表示一个不可变、原始数据的类文件对象
        const url = window.URL.createObjectURL(blob) // 生成一个url:可以指向 File 对象或 Blob 对象。
        
        const dom = document.createElement('a')
        dom.href = url
        dom.download = decodeURI(filename) // 用dom的download下载,可以设置默认文件名
        dom.style.display = 'none'
        document.body.appendChild(dom)
        dom.click()
        dom.parentNode.removeChild(dom) // 释放内存
        window.URL.revokeObjectURL(url) // 释放内存
    }
    

    !!!此处有个坑,需要特别注意:

    文件流是从接口拿的,请求的axios需要配置 responseType !!!

    export const get_xxx = (params) => {
      return axios({
        method: 'get',
        url: "/xxxx", 
        responseType: "blob", // 拿文件流需要配置这个
        params
      })
    }
    
    // axios 内:
    // `responseType` 表示服务器响应的数据类型,
    //  可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
    responseType: 'json', // 默认的
    
  3. 最终封装

    /**
     * 方法说明 下载文件, 有2种形式, 1. url (例如: http://xxxxx/a.zip) 2. 文件流, 且需要默认文件名
     * @method downFile
     * @param{object} url data filename headerType
     *
     * 使用示例:
     *    形式1: downFile({ url: 'http://xxxxx/a.zip' })
     *    形式2: downFile({
     *            data: 'xxx文件流',
     *            filename: '模板.xlsx', // 可选, 默认'模板.xlsx'
     *            headerType: 'application/octet-stream;charset=utf-8', // 可选 默认'application/octet-stream;charset=utf-8'
     *          })
     */
    
    export const downFile = function (obj) {
      if (obj.url) { // 形式1 url (例如: http://xxxxx/a.zip)
          window.open(obj.url)
      } else { // 形式2  文件流, 且需要默认文件名
        const { data, filename = '模板.xlsx', headerType = 'application/octet-stream;charset=utf-8' } = obj
    
        const blob = new Blob([data], { type: headerType })
        const url = window.URL.createObjectURL(blob)
    
        const dom = document.createElement('a')
        dom.href = url
        dom.download = decodeURI(filename) // 用dom的download下载,可以设置默认文件名
        dom.style.display = 'none'
        document.body.appendChild(dom)
        dom.click()
        dom.parentNode.removeChild(dom) // 释放内存
        window.URL.revokeObjectURL(url) // 释放内存
      }
    }
    

2. 文件上传

先说一下小坑,憋着难受 ( ̄. ̄||)

如果响应头: Access-Control-Allow-Origin: *  
白名单直接配置了*的话,前端就不能带cookie !!!!
否则接口会报跨域的错误

接下来继续讲文件上传

  1. 用ui组件 (此处用的iview)

    <Upload
      type="drag"
      name="excelFile" // 如果接口需要加参数则加个name
      :headers="headers"
      action="http://xxxxxx/import">
        <div style="padding: 10px 0">
          <Icon type="ios-cloud-upload" size="52" style="color: #39f"></Icon>
          <p>点击或拖拽上传文件</p>
        </div>
    </Upload>
    
    注意点:公司内部平台,一般来说,都需要设置请求头
    不要加Content-Type: multipart/form-data; ( 文件上传默认会自动适配Content-Type, 千万不要在额外加 )
    其他的请求头需要多少,就自行加上
    此处有个坑点 ui组件配置 with-credentials(支持发送 cookie 凭证信息, 默认false,如果要改为true 要小心),这个坑点就是上面写的
    

    然后,如果接口需要加参数,则加个 name="excelFile" formData.jpg

  2. 自己写上传

    1. 用axios上传

      最好,重新引入axios,因为,项目内的axios可能被封装过,Content-Type 可能已经被动过了,要文件上传能够成功,这个Content-Type不能动,他会自动识别到是文件上传multipart/form-data + 文件标识

      import Axios from 'axios'
      
      const upload = (file) => {
        // file 是 File对象
        const formData = new FormData()
        formData.append('excelFile', file) // 接口需要传参excelFile,具体情况具体分析
        let res = await Axios.post('http://xxxx/import', formData, {
          headers: {
            'Token': xxx,
            'System-Host': xx
          }
        })
        res = res.data
        console.log(res)
      }
      
    2. 用fetch上传

      const upload = (file) => {
        // file是 File 对象
        const formData = new FormData()
        formData.append('excelFile', file) // 接口需要传参excelFile,具体情况具体分析
        let res = await fetch('http://xxxxx/import', {
          body: formData,
          credentials: 'omit', // 不传cookie
          headers: {
            'Token': xxx,
            'System-Host': xx
          },
          method: 'POST' // *GET, POST, PUT, DELETE, etc.
        })
        res = await res.json() 
        console.log(res)
      }