在前端項目中常常遇到上傳文件的需求,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