Ant Design 使用Upload组件默认方式上传图片到阿里云OSS

8,804 阅读2分钟

背景

近来做了一个管理后台,采用的AntDesignPro脚手架,阿里版的React全家桶,包含Ant Design组件库,Dva状态管理,权限模块,国际化,主题定制等等称成熟的解决方案,当然这不是今天要将的重点。

今天要谈论的是使用Upload默认方式上传到OSS,为啥要用默认的方式上传呢?

No reason ! Why not !!

!!!! 现在官方已经更新相关示例和api,建议参考官方示例:

ant.design/components/…

正文

直接上代码,试试代码自解释:


import CryptoJS from 'crypto-js';
import Base64 from 'base-64';

...

const uploadButton = (
   <div>
     <Icon type={payImgLoading ? 'loading' : 'plus'} />
     <div className="ant-upload-text">Upload</div>
   </div>
 );
 
...

<Upload
  action="http://xxxx.oss-cn-shanghai.aliyuncs.com"
  accept="image/*"
  listType="picture-card"
  className="avatar-uploader"
  showUploadList={false}
  beforeUpload={this.beforeUpload}
  onChange={this.handleChange}
  data={{
    key: todayKey + "/${filename}",
    policy: policyBase64,
    OSSAccessKeyId: accessKeyId,
    success_action_status: 200,
    signature,
  }}
>
  {
     payImgUrl ? 
     <img 
        src={imgUrl} 
        alt="avatar" 
        style={{ width: '100%' }} 
     /> : 
     uploadButton
     
  }
</Upload>

以上代码重点关注Upload组件的action属性和data属性,一个是图片上传接口地址,当然可以直接是 OSS 对象存储地址; 而核心在data属性上:

  • key: 文件路径采用:日期文件夹 + 文件名

需要注意的是后面的 "/${filename}",这里不是反引号,整体是字符串,filename是形参,不能填入真实文件名;

  • policy: policyBase64
const policyText = {
  "expiration": "2028-01-01T12:00:00.000Z", // 设置该Policy的失效时间
  "conditions": [
    ["content-length-range", 0, 1048576000] // 设置上传文件的大小限制
  ]
};
const policyBase64 = Base64.encode(JSON.stringify(policyText))
  • OSSAccessKeyId: 阿里云OSS keyid
  • success_action_status:200
  • signature: 建议采用后台签名,下面是前端签名方法,accessSecret是阿里云OSS秘钥
const bytes = CryptoJS.HmacSHA1(policyBase64, accessSecret, { asBytes: true });
const signature = bytes.toString(CryptoJS.enc.Base64); 

上面使用到两个加密库

import CryptoJS from 'crypto-js';// "base-64": "^0.1.0"
import Base64 from 'base-64';//  "crypto-js": "^3.1.9-1"

今天这个编辑器老是自动滚动,不啰嗦了,在配置中遇到问题请留言吧...

福利,附上完整代码

/* eslint-disable no-template-curly-in-string */

import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
import moment from 'moment';
import CryptoJS from 'crypto-js';
import Base64 from 'base-64';
import {
  Card, Form, Input, Divider, Icon, Upload, message, Button,
  Table, Modal, InputNumber, Select, Popconfirm
} from 'antd';

const todayKey = moment().format('YYYYMMDD');
const host = "http://xxxx.oss-cn-shanghai.aliyuncs.com";
const accessKeyId = "xxxxx";
const accessSecret = "xxxxxx";
const policyText = {
  "expiration": "2028-01-01T12:00:00.000Z", // 设置该Policy的失效时间,
  "conditions": [
    ["content-length-range", 0, 1048576000] // 设置上传文件的大小限制
  ]
};
const policyBase64 = Base64.encode(JSON.stringify(policyText))
const bytes = CryptoJS.HmacSHA1(policyBase64, accessSecret, { asBytes: true });
const signature = bytes.toString(CryptoJS.enc.Base64); 


@Form.create()
@connect(({loading, usermanage }) => ({
  userList: usermanage.userList,
  loading: loading.models.usermanage,
}))
class TableList extends PureComponent {

  state = {
    payImgLoading: false,
    payImgUrl: ''
  };
  

  beforeUpload = (file) => {
    // 检查图片类型
    const isJPG = file.type === 'image/jpeg';
    const isPNG = file.type === 'image/png';
    const isBMP = file.type === 'image/bmp';
    const isGIF = file.type === 'image/gif';
    const isWEBP = file.type === 'image/webp';
    const isPic = isJPG || isPNG || isBMP || isGIF || isWEBP;
    if (!isPic) {
      message.error('请上传图片');
      return;
    }
    const isLt5M = file.size / 1024 / 1024 < 5;
    if (!isLt5M) {
      message.error('上传图片必须小于 5MB!');
      return;
    }
    return isPic&&isLt5M;
  }

  handleChange = ({ file }) => {
    if (file.status === 'uploading') {
      this.setState({ payImgLoading: true });
      return;
    }
    if (file.status === 'done') {
      this.setState({
        payImgUrl: `${host}/${todayKey}/${file.name}`,
        payImgLoading: false,
      });
    }
  }


  render() {
    
    const uploadButton = (
      <div>
        <Icon type={payImgLoading ? 'loading' : 'plus'} />
        <div className="ant-upload-text">Upload</div>
      </div>
    );
  
    return (
        <Upload
           action={host}
           accept="image/*"
           listType="picture-card"
           className="avatar-uploader"
           showUploadList={false}
           beforeUpload={this.beforeUpload}
           onChange={this.handleChange}
           data={{
             key: todayKey + "/${filename}",
             policy: policyBase64,
             OSSAccessKeyId: accessKeyId,
             success_action_status: 200,
             signature,
           }}
        >
           {
               payImgUrl ? 
               <img src={payImgUrl} alt="avatar" style={{ width: '100%' }} /> :
               uploadButton   
           }
        </Upload>    
    );
  }
}