关于上传图片或文件给后台时的几种情况处理

一、工作中经常会遇到的一些场景

​ 前端项目中总是不可避免的会涉及到向后台提交图片、文件及视频,之前遇到这样的场景内心总是一紧,因为前期几次和后台的对接都是走了很多弯路,当然了这跟自己的经验缺乏,对文件之间的类型转换了解不清以及各大平台上用法不一了接不深导致的(这里主要讲H5跟微信小程序)。为了增加印象,也为了后面少走弯路,特此记录。

​ 1、Arraybuffer、Blob、File、Buffer、base64图片详解、作用以及相互转化。

​ 2、如何向后端传递二进制流文件。

二、base64图片、Arraybuffer、Blob、File、Buffer、详解、作用以及相互转化。

1、base64图片

​ (1)什么是base64编码:图片的base64编码就是可以将一张图片数据编码成一串字符串,使用该字符串代替图像地址url。

​ (2)使用base64图片的缺点:1、增加css文件的大小。2、浏览器兼容性。3、解析css的时间增长。

​ (3)使用base64图片的优点:1、无额外请求。2、可像独立图片一样使用,比如背景图片重复使用等。3、没有跨域问题,无需考虑缓存,文件头或者cookies问题。

​ (4)**处理(固定格式)**:

​ (5)总结:使用base64不代表性能优化,使用base64减少了http请求,但是增加了css文件的体积,css文件体积增大意味着CRP的阻塞。

2、Blob

  1. 定义:大致上你可以理解为Blob就是一块二进制数据,读取很麻烦,不能写.

  2. 创建:

    1
    2
    3
    // 直接创建:

    const blob = new Blob( array, options );
    1
    2
    3
    // 大部分情况,**从ArrayBuffer转过来**,也是直接创建:

    const blob = new Blob([arrayBuffer.buffer],{type:"xxx/xxx"});
    1
    2
    3
    // 从网络获取:

    xhr.responseType = 'blob';
  3. 用途:文件下载、本地文件预览

3、File

  1. 定义:File是继承于Blob的,大部分你都可以直接当成Blob对象使用
  2. **创建: ** new File()的功能是将blob对象转为文件格式,这个文件就相当于是使用 选择的FileList对象,一般插件上传本地文件得到的就是这个.

4、Arraybuffer

  1. 定义:ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区,高深点说,arraybuffer可以理解为一段内存;通俗点的话就是arraybuffer是一个二进制文件集合,只不过这个数组有点特殊,你只能看不能改。

  2. 创建:

    1
    2
    3
    // 直接创建:

    const arrayBuffer = new ArrayBuffer(length);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //  网络获取
    // 响应类型需要设置为arraybuffer,后面接收到的data要使用base64处理成可显示的形式

    wx.request({

          url: url,

          method: 'GET',

          // dataType: 'json',

          responseType: 'arraybuffer',         //将原本按文本解析修改为arraybuffer

          success: function(res) {

            this_.setData({

              imgUrl: wx.arrayBufferToBase64(res.data)

            })

          }

        })
    1
    2
    3
    //  从File或Blob获取:

    const arrayBuffer = await file.arrayBuffer();
  3. 用途: 因为ArrayBuffer只能读不能写,没啥用.

5、Buffer

  1. 定义:Buffer 对象用于表示固定长度的字节序列,是Nodejs里的概念.

  2. 创建:

    1
    2
    3
    4
    5
    6
    7
    // 直接创建:

    // 1、一种是申请固定大小的Buffer
    const buf = Buffer.alloc(5); //申请5字节大小的Buffer

    // 2、一种是根据其他数据来转成Buffer
    const buf = Buffer.from(arrayBuffer.buffer); //arrayBuffer指TypedArray
  3. 用途:一般用来文件读写

6、相互转化

  1. ArrayBuffer转Blob

    1
    2
    3
    //  使用构造函数Blob

    const blob = new Blob([arrayBuffer],{type:"xxx/xxx"});
  2. Blob转ArrayBuffer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //  对兼容性有要求的话使用FileReader

    const fileReader:FileReader = new FileReader();

    fileReader.addEventListener("load",(event)=>{
    const arrayBuffer = event.target.result;
    //...
    })

    fileReader.readAsArrayBuffer(file);
  3. ArrayBuffer转Buffer

    1
    2
    3
    //  使用Buffer.from

    const buf = Buffer.from(arrayBuffer.buffer);
  4. Buffer转ArrayBuffer

    1
    2
    3
    //  Buffer的实例维护了一个属性buffer,亦即ArrayBuffer

    const arrayBuffer = buf.buffer

三、如何向后端传递二进制流文件

1、new FormData()(h5)

​ new FormData()就是将文件转成二进制流,它就是binary。向表单中追加属性值用append()方法。

  1. 传二进制到服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 核对广告卡-上传文件
    export function uploadImage(url: any, data: any) {
    return service({
    url: url,
    method: "post",
    data: data,
    headers: {
    'Content-Type': 'multipart/form-data'
    }
    });
    }

    // 核验文件
    const uploadFile = async () => {
    if(state.fileData.raw == undefined) {
    ElMessage.error('请上传文件后再提交!!');
    return
    }
    const formData = new FormData();
    formData.append('file', state.fileData.raw);
    const res: any = await uploadImage(formData);
    state.uploadData = res.data;
    };
  2. 传二进制到oss(第一步:获取oss签名,第二步:通过oss地址上传到)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 图片上传至oss
    const picUpload = async (file) => {
    // 获取oss上传签名
    const { data: signData } = await imgSign();
    const ossData = new FormData();
    const filename = myUtils.randomName(file.file.name, 10);
    //图片名称
    const keyValue = signData.dir + filename;
    //文件名
    ossData.append("name", file.file.name);
    ossData.append("key", keyValue);
    ossData.append("policy", signData.policy);
    ossData.append("OSSAccessKeyId", signData.accessid);
    ossData.append("success_action_status", '200');
    ossData.append("signature", signData.signature);
    ossData.append("file", file.file);
    uploadImage(signData.host, ossData).then(() => {
    const Url = process.env.VUE_APP_OSS_URL + '/' + keyValue;
    const imageUrl = {
    url: Url
    }
    state.imgList.push(imageUrl);
    });
    };

2、小程序中使用wx.uploadFile(没有FormData)

  1. 得到一个string类型的对象字符串(多次踩坑)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    wx.uploadFile({
    url: API.OSSIMGAGEUPLOAD,
    filePath: fileUrl,
    name: 'file',
    header: {
    // 让每个请求携带自定义token 请根据实际情况自行修改
    'Authorization': `Bearers ${wx.getStorageSync('token')}`
    },
    success(res) {
    let newFileList = that.data.fileList;
    let newImgList = that.data.imgList;
    // 得到一个string类型的对象字符串
    let parseObject = JSON.parse(res.data);
    newFileList.push({
    url: parseObject.data.url,
    name: parseObject.data.fileName
    });
    newImgList.push(parseObject.data.url);
    that.setData({
    fileList: newFileList,
    imgList: newImgList,
    uploadText: ''
    });
    },
    });

四、后端返回二进制流

1、返回图片的二进制流

  1. response-type为blob类型

    • 把response-type改为blob类型

    • 在请求后端接口返回data时,调用window的URL方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      //完整代码
      <img :src="imgUrl " />

      axios.get('url',{
      params:{
      key:this.key
      },
      responseType: 'blob', //这里是声明期望返回的数据类型,为blob
      }).then(response => {
      this.imgUrl = window.URL.createObjectURL(res.data); //这里调用window的URL方法
      })
  2. response-type为arraybuffer类型

    • 把response-type改为arraybuffer类型

    • 在请求后端接口返回data时,将其转为base64

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      axios.get('url',{
      params:{
      a: this.a
      },
      responseType: 'arraybuffer' //这里是声明期望返回的数据类型,为arraybuffer
      }).then(response => {
      //这里的data数据是后台返回来的,byte是params中的键值 这里是将二进制流转换成了base64
      const bufferUrl = btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), ''));
      this.imgUrl = 'data:image/png;base64,' + bufferUrl;
      })

2、返回文件的二进制流

  1. 修改response

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 资金池明细 导出excel
    export const capitalRecordExcel = (data: any) => {
    return createAxios({
    url: '/change/export',
    method: 'POST',
    data: data,
    responseType: 'blob',
    })
    }
  2. 转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 导出
    const onExport = async () => {
    const res: any = await capitalRecordExcel({ ...searchForm })
    const xlsx = 'application/vnd.ms-excel'
    const blob = new Blob([res], { type: xlsx }) //转换数据类型
    const a = document.createElement('a') // 转换完成,创建一个a标签用于下载
    a.download = '资金池明细' + new Date().getTime() + '.xlsx'
    a.href = window.URL.createObjectURL(blob)
    a.click()
    a.remove()
    }