zoukankan      html  css  js  c++  java
  • Ant Design Upload 组件上传文件到云服务器

    在前端项目中经常遇到上传文件的需求,ant design 作为 react 的前端框架,提供的 upload 组件为上传文件提供了很大的方便,官方提供的各种形式的上传基本上可以覆盖大多数的场景,但是对于不同的服务器平台,可能实现方式会有所不同,尤其最近使用了阿里云作为服务器上传,就需要自定义上传行为才能满足需求,因此针对不同平台文件上传的异同和 upload 组件使用中遇到的问题做一个简单总结,希望可以对遇到类似问题的小伙伴有所帮助。

    首先这里大致总结了几个不同平台服务器上传方式的异同:

        服务器平台          上传凭证            请求方式 method         文件格式 content-type      
    七牛云 key、token POST  multipart/form-data
    腾云云 key、url POST  multipart/form-data
    阿里云 key、url PUT application/octet-stream

    upload 组件默认提供的请求方式是POST,并且文件的提交类型是 form-data 格式,因此使用 upload 组件可以直接上传文件到七牛云和腾讯云,但是在上传到阿里云的时候,就需要对上传操作进行配置(需要吐槽一句,同样是自家的产品,为什么请求方式不统一),为此官方提供了 customRequest 这个 api 并且FAQ中提供了参考文档:https://github.com/react-component/upload#customrequest

    接下来看不同的平台具体上传实现上的基本代码:

    七牛云上传方式比较简单,官方提供了统一的上传地址 https://upload-z2.qiniu.com,只要获取上传凭证就可以了,如下:

                      文件上传的组件部分

    对应的主要方法(这些方法在不同平台的上传过程中都是可用的,内部具体操作可能会有所不同):

                      文件上传相应方法

    腾讯云和七牛云的上传方式类似,不同的是上传地址是通过请求凭证获取到的,因此组件属性中的 aciton 字段的需要通过请求获得:如下:

    阿里云和腾讯云上传的不同点在于请求方式和文件格式不同,而 upload 组件默认属性不支持对应的格式,因此需要自定义上传行为,具体实现如下:

    import React, { PureComponent } from 'react';
    import { Upload, Icon, message } from 'antd';
    import apis from '@/services/api';
    import axios from 'axios';
    
    class Uploader extends PureComponent {
      state = {
        key: '',
        url: '',
        imageUrl: '',
      }
    
      // 这里可以做上传之前的操作,比如文件大小的校验等
      beforeUpload = async (file) => {
        const res = await this.fetchUploadToken();
        return res;
      }
    
      // 获取上传凭证
      fetchUploadToken = async () => {
        const params = {
          quantity: 1,
          module: 3,
          fileType: 1,
        };
        const res = await apis.fileSign(params);
        const { d, m } = res;
        if (m === 'success') {
          const { key, url } = d.l[0];
          this.setState({ key, url });
          return true;
        } else {
          return false;
        }
      }
    
      render() {
        const { imageUrl, url, key } = this.state;
        const that = this;
        const uploadProps = {
          name: 'file',
          showUploadList: false,
          multiple: false,
          accept: '.png, .jpg, .jpeg, .gif',
          action: url,
          beforeUpload: that.beforeUpload,
          // 这里需要指定文件上传的content-type
          headers: {
            'Content-Type': 'application/octet-stream',
          },
          // 自定文件上传的方法,覆盖组件的 onChange 方法,可以定义上传不同阶段的行为(由 axios 默认提供)
          onStart(file) {
            console.log('onStart', file, file.name);
          },
          onSuccess(ret, file) {
            console.log('onSuccess', ret, file);
            that.props.getData(key);
          },
          onProgress({ percent }, file) {
            console.log('onProgress', `${percent}%`, file.name);
          },
          onError(err) {
            console.log('onError', err);
          },
          customRequest({
            action,
            file,
            headers,
            onError,
            onProgress,
            onSuccess,
            withCredentials,
          }) {
            // 使用 FileReader 将上传的文件转换成二进制流,满足 'application/octet-stream' 格式的要求
            const reader = new FileReader();
            reader.readAsArrayBuffer(file);
            let fileData = null;
            reader.onload = (e) => {
              // 在文件读取结束后执行的操作
              fileData = e.target.result;
              // 使用 axios 进行文件上传的请求
              axios.put(action, fileData, {
                withCredentials,
                headers,
                onUploadProgress: ({ total, loaded }) => {
                  // 进行上传进度输出,更加直观
                  onProgress({ percent: Math.round(loaded / total * 100).toFixed(2) }, file);
                },
              }).then(response => {
                  onSuccess(response, file);
                })
                .catch(onError);
            };
            return {
              abort() {
                console.log('upload progress is aborted.');
              },
            };
          },
        };
        return (
          <div>
            <Upload {...uploadProps}>
              { imageUrl ? <img src={imageUrl} /> : <Icon type='plus' /> }
            </Upload>
          </div>
        );
      }
    }
    
    export default Uploader;

    使用如上 PUT 请求上传文件,在浏览器中打印信息格式如下:

    总结:图片上传一直是前端令人头疼的问题,不同的服务器平台对请求方式和文件格式可能有不同的要求,因此在上传之前需要做对应的文件处理,而且因为环境不同,还需要和后端合作处理跨域的问题,尽管很多优秀的组件已经提供了响应的处理方法,但是如果对组件实现原理和api不够了解,可能依旧无法实现一些具体的功能,所以在实现文件上传的时候,需要多研究,多总结,针对遇到的问题要及时记录,避免再次踩坑。

    【参考资料】:

    https://github.com/react-component/upload/blob/master/examples/customRequest.js

    vue前端上传文件到阿里云oss的两种方式,put文件流上传,multipartUpload直接上传

    前端上传文件至阿里云

    FileReader - Web API 接口参考 | MDN

  • 相关阅读:
    es6 简介
    npm 快速开发技巧
    css清除浮动方法
    mui 总结
    7种 JS 创建对象的经典方式
    JavaScript 的 this 原理
    使用定时器
    dom 操作及方法
    JavaScript的6种继承方式及其优缺点
    贪吃蛇游戏代码
  • 原文地址:https://www.cnblogs.com/wx1993/p/10496937.html
Copyright © 2011-2022 走看看