初衷
最近接到需求,要求用户在浏览器前端点击上传button,实现图片或者视频的上传,并在button旁边设置预览功能。
图片或者文件这类文件资源需要上传到阿里云的OSS对象存储系统,在这里记录一下踩坑过程。

步骤
因为我们用到了阿里云的OSS,所以第一步是 import
需要的模块:
import OSS from 'ali-oss';
在设计组件的时候,我用了 antd 的 upload 控件,主要使用 upload 的组件的 beforeUpload 函数。
先定义组件需要的 props :
1 2 3 4 5 6
| const uploadProps = { beforeUpload: beforeUpload, fileList: fileList, accept: 'video/*', listType: 'picture-card', };
|
这是一个上传 video 的控件,accept
接受的'video/*'
表示上传的文件类型只能是 video 类型。
具体的类型可以看 MDN 上的说明
然后再定义 beforeUpload 函数:
1 2 3 4 5 6 7 8 9 10 11 12
| const beforeUpload = file => { const floder = 'kyc' let reader = new FileReader();
reader.readAsDataURL(file); reader.onloadend = () => { UploadToOss(this, floder, file) .then(data => { changeShow(false) return data; }); };
|
在 beforeUpload
中 我们先声明一个 fileReader
对象,用来存储我们从 input
控件中上传的文件对象,具体可见 MDN 的描述, floder
为bucket下的文件夹

我们在 FileReader
中调用了一个 UploadToOss
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const UploadToOss = (self, path, file) => { const uploadPath = (path, file) => { return `${path}/${file.name.split('.')[0]}-${file.uid}.${file.type.split('/')[1]}`; }; const url = uploadPath(path, file); return new Promise((resolve, reject) => { client(self) .multipartUpload(url, file) .then(data => { resolve(data); }) .catch(error => { reject(error); }); }); };
|
uploadPath
定义上传的 url
,然后返回一个 Promise
调用 client
的 multipartUpload
函数,将文件上传到阿里云的 OSS 。下面来看 client
的定义:
1 2 3 4 5 6 7
| const client = () => { return new OSS({ region: 'oss-cn-hangzhou', accessKeyId: 'xxxx', accessKeySecret: 'xxx', bucket: 'tik-file', });
|
其中的 region
是 OSS 的区域,默认是 oss-cn-hangzhou
, 具体可以看你的OSS配置,accessKeyId
和 accessKeySecret
是你的认证的账号密码,bucket
是你的文件 bucket.
tips:文章最后附上整个组件的代码。
但是仅仅这样还是不能给上传的,因为上传的过程中涉及到浏览器的跨域问题,浏览器默认是阻止跨域的,要解决这个办法,需要配置阿里云的 OSS,进入到你的阿里云 OSS 控制台, 然后进行如下配置:
tips: 阿里云的OSS还是很好用很便宜,是按量计费的,我本地的上传了几百M的文件才花1毛钱,不得不说还是很良心,适合个人图床什么的。

实现以上配置,就可以上传你的文件到阿里云OSS了,上传图片的原理是一样的,只需要修改props
中的 accept
类型为 image/*
就行。
OK,That’s all.
完整代码
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import OSS from 'ali-oss'; import React, { useState } from 'react'; import { Upload, Icon, Spin } from 'antd';
const cdnPath = '你的cdn地址';
const VideoUploader = props => {
// 上一个组件传来的修改资源URL的函数,可用于展示远程的资源 const changeSrc = props.changeSrc; const [show, changeShow] = useState(false);
const fileList = []; const client = self => { return new OSS({ region: 'oss-cn-hangzhou', accessKeyId: 'accessKeyId', accessKeySecret: 'accessKeySecret', bucket: 'bucket', }); };
const uploadPath = (path, file) => { return `${path}/${file.name.split('.')[0]}-${file.uid}.${file.type.split('/')[1]}`; };
const UploadToOss = (self, path, file) => { const url = uploadPath(path, file); return new Promise((resolve, reject) => { client(self) .multipartUpload(url, file) .then(data => { resolve(data); }) .catch(error => { reject(error); }); }); };
const beforeUpload = file => { changeShow(true); const floder = 'kyc'; let reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = () => { UploadToOss(this, floder, file) .then(data => { changeShow(false); return data; }) .then(data => { changeSrc(`${cdnPath}${data.name}?uploadId=video`); }); };
return false; };
const uploadProps = { beforeUpload: beforeUpload, fileList: fileList, accept: 'video/*', listType: 'picture-card', };
const uploadButton = ( <div> <Icon type="plus" /> <div className="ant-upload-text">Upload</div> </div> );
return ( <div> {show === true ? ( <Spin style={{ position: 'relative', left: '40px' }} /> ) : ( <Upload {...uploadProps}>{uploadButton}</Upload> )} <br /> </div> ); };
export default VideoUploader;
|