前端上传文件程序开发
基本流程
在实际项目中,一般采用分布式及微服务的 web 业务系统中,文件的上传和下载都是直接在前端来实现对 oss 的操作。也就是前端直接上传,不通过自己的服务器。这样能够实现系统无阻碍的横向扩展。另一个原因是如果要把文件保存在运行 web 服务器的同一台服务器上时,那么在文件上传时可能会占满带宽,影响 web 的访问。分开存储不占服务器带宽。
阿里 OSS 提供了三种前端直传方式:
浏览器签名后直接上传 OSS(无需服务端干预)
浏览器请求服务器签名地址后上传(需要服务端配合)
浏览器请求服务器签名地址后上传并回调服务端(需要服务端配合)
实际生产环境考虑到安全性必须选择第二种,需要服务端与前端相配合,当安全性要求不高时可采用第一种方式。
下面用的封装方法是第二种
且用到了表单验证,需要注意的是表单验证受控时需要做处理。
**
服务端签名回传,并且设置回调
**
import { Form, Upload, message, Button } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import React from 'react'
class AliyunOSSUpload extends React.Component {
state = {
OSSData: {},
};
async componentDidMount() {
await this.init();
}
init = async () => {
try {
const OSSData = await mockGetOSSData(); // 后端返回接口数据
this.setState({
OSSData,
});
} catch (error) {
message.error(error);
}
};
// mockGetOSSData = () => ({
// dir: 'user-dir/',
// expire: '1577811661',
// host: '//www.mocky.io/v2/5cc8019d300000980a055e76',
// accessId: 'c2hhb2RhaG9uZw==',
// policy: 'eGl4aWhhaGFrdWt1ZGFkYQ==',
// signature: 'ZGFob25nc2hhbw==',
// });
onChange = ({ fileList,file }) => {
if(file.status ==='done'){
//上传成功之后,把文件的key,设置为表单某个字段的值16
// (父组件)const [formobj]=ProForm.useForm()
// formobj.setFieldsValue({'cover':filekey}) <form form={formobj}>
//******* !!!!!!!!一定要注意组件不能和form.item 形成受控组件,需要用div或其他包着 */
this.props.setCoverkey= (file.key)
message.success('上传成功')
}
// const { onChange } = this.props;
// console.log('Aliyun OSS:', fileList);
// if (onChange) {
// onChange([...fileList]);
// }
};
onRemove = file => {
const { value, onChange } = this.props;
const files = value.filter(v => v.url !== file.url);
if (onChange) {
onChange(files);
}
};
getExtraData = file => {
const { OSSData } = this.state;
return {
key: file.key,
OSSAccessKeyId: OSSData.accessId,
policy: OSSData.policy,
Signature: OSSData.signature,
};
};
beforeUpload = async file => {
const { OSSData } = this.state;
const expire = OSSData.expire * 1000;
//签名过期,重新获取
if (expire < Date.now()) {
await this.init();
}
//定义放图片的目录
const dir = 'osspic'
const suffix = file.name.slice(file.name.lastIndexOf('.'));
const filename = Date.now() + suffix;
file.key = OSSData.dir + dir+filename;//额外参数中,在云存储中存储的文件key
file.url = OSSData.host+OSSData.dir + dir+filename; //上传用于显示的内容
return file;
};
render() {
const { value } = this.props;
const props = {
accept:this.props.accept||'',//可接收的文件格式,如'image/*'
name: 'file',
fileList: value,
action: this.state.OSSData.host,
onChange: this.onChange,
onRemove: this.onRemove,
data: this.getExtraData,
beforeUpload: this.beforeUpload,
maxCount:1,
listType:'picture',
};
return (
// 表单验证可加<ProForm.Item name='cover'> 需要匹配验证
<Upload {...props}>
{...props.children}
</Upload>
);
}
}