在前端项目中常常遇到上传文件的需求,ant design 做为 react 的前端框架,提供的 upload 组件为上传文件提供了很大的方便,官方提供的各类形式的上传基本上能够覆盖大多数的场景,可是对于不一样的服务器平台,可能实现方式会有所不一样,尤为最近使用了阿里云做为服务器上传,就须要自定义上传行为才能知足需求,所以针对不一样平台文件上传的异同和 upload 组件使用中遇到的问题作一个简单总结,但愿能够对遇到相似问题的小伙伴有所帮助。html
首先这里大体总结了几个不一样平台服务器上传方式的异同:前端
服务器平台 | 上传凭证 | 请求方式 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。vue
接下来看不一样的平台具体上传实现上的基本代码:react
七牛云上传方式比较简单,官方提供了统一的上传地址 https://upload-z2.qiniu.com,只要获取上传凭证就能够了,以下:ios
文件上传的组件部分git
对应的主要方法(这些方法在不一样平台的上传过程当中都是可用的,内部具体操做可能会有所不一样):github
文件上传相应方法axios
腾讯云和七牛云的上传方式相似,不一样的是上传地址是经过请求凭证获取到的,所以组件属性中的 aciton 字段的须要经过请求得到:以下:segmentfault
阿里云和腾讯云上传的不一样点在于请求方式和文件格式不一样,而 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