以前公司上传文件都是后端给个请求地址,前端按照后端需要的格式发送请求,后端返回给前端一个服务器可以访问的文件地址,前端再连同其他表单数据进行提交。新公司前端是自己上传金山云直接拿到服务器可以访问的地址(当然上传金山云的签名需要后端返回),再跟其他表单数据请求提交。下面说一下流程
框架:@vue-cli4.5.11
UI库: ant-design-vue1.7.5
相关文档参考:对象存储(KS3)POST Object-金山云
src/api/common.js
import request from '@/utils/request'
export default class CommonServer {
// 获取金山云上传签名
static getKsOssSign (params) {
return request({
url: '/ks3/policy/signature',
method: 'get',
params
})
}
}
src/utils/oss.js
import moment from 'moment' //npm或yarn安装moment
// 文件扩展名提取
export const fileType = fileName => {
return fileName.substring(fileName.lastIndexOf('.') + 1)
}
/**
* oss路径定义
* @param file
* @param customFileType 自定义的扩展名
*/
export const ossPath = (file, customFileType) => {
const folder = moment().format('YYYY-MM-DD')
const name = moment().format('YYYY-MM-DD-HH-mm-ss-SSS')
if (file.name) {
const type = fileType(file.name)
return `项目名称(金山云上创建的对应项目文件名)/upload/${
folder}/${
type}/${
name}.${
type}`
} else if (customFileType) {
return `项目名称(金山云上创建的对应项目文件名)/upload/${
folder}/${
customFileType}/${
name}.${
customFileType}`
}
}
src/utils/oss.js
import CommonServer from '@/api/common'
/**
* 金山云上传
* @returns {Promise}
*/
export const ksOssUpload = (file, customFileType) => {
return new Promise((resolve, reject) => {
const key = ossPath(file, customFileType)
const params = {
fileName: key }
CommonServer.getKsOssSign(params).then(res => {
const {
accessid, policy, signature, host } = res
const formData = new FormData()
formData.append('acl', 'public-read')
formData.append('key', key)
formData.append('signature', signature)
formData.append('KSSAccessKeyId', accessid)
formData.append('policy', policy)
formData.append('file', file)
axios.post(`https://${
host}`, formData).then(res => {
const {
status } = res
if (status === 200) {
const data = {
url: `https://${
host}/${
key}`,
type: file.name ? fileType(file.name) : customFileType
}
resolve(data)
} else {
reject(res)
}
}).catch(err => {
reject(err)
})
}).catch(err => {
})
})
}
src/utils/oss.js
import {
message } from 'ant-design-vue'
/**
* 上传文件大小限制
* @param file
* @param fileMaxSize
* @returns {boolean}
*/
export const isMaxFileSize = (file, fileMaxSize = 1) => {
if (!file) return false
const isMaxSize = file.size / 1024 / 1024 < fileMaxSize
if (!isMaxSize) {
message.error(`上传文件大小不能超过${
fileMaxSize}MB!`)
return false
}
return true
}
/**
* 文件最大数量限制
* @param fileList
* @param maxLength
* @returns {boolean}
*/
export const isMaxFileLength = (fileList = [], maxLength = 3) => {
if (fileList.length >= maxLength) {
message.error(`最多上传${
maxLength}个文件`)
return false
}
return true
}
/**
* 判断上传是否为图片
* @param file
* @returns {boolean}
*/
export const isImageFile = file => {
if (!file) return false
const types = [
'image/png',
'image/gif',
'image/jpeg',
'image/jpg',
'image/bmp',
'image/x-icon'
]
const isImage = types.includes(file.type)
if (!isImage) {
message.error('上传文件非图片格式!')
return false
}
return true
}
/**
* 判断图片是否损坏
* @param file
*/
export const isNormalImage = file => {
return new Promise((resolve, reject) => {
if (!file) return
const image = new Image()
image.src = file
image.onload = () => {
resolve({
status: 1, message: '加载成功' })
}
image.onerror = () => {
// eslint-disable-next-line prefer-promise-reject-errors
reject({
status: 0, errMsg: '图片损坏,请重新上传' })
}
})
}
***.vue, 下面以ant-design-vue上传组件为例,这里只展示上传逻辑
<template>
...
<a-upload v-bind="uploadProps">
<a-button
type="primary"
:loading="loading"
icon="upload"
>
点击上传
</a-button>
</a-upload>
...
</template>
<script>
import {
isMaxFileLength, isMaxFileSize, ksOssUpload } from '@/utils/oss'
...
data () {
return {
uploadProps: {
accept: '*',
showUploadList: false,
customRequest: async (param) => {
if (!param.file) return
if (!isMaxFileLength(this.mediaList, this.maxLength)) return
if (!isMaxFileSize(param.file, 10)) return
await this.handleUpload(param.file)
}
},
maxLength:3,
mediaList: [],
loading: false
}
},
methods{
...
// 上传
async handleUpload (file) {
try {
this.loading = true
this.$message.loading('文件上传中')
const {
url } = await ksOssUpload(file) //这里的就是上面src/utils/oss.js里面的上传
this.mediaList.push(url)
this.loading = false
this.$message.success('文件上传成功!')
} catch (e) {
this.loading = false
this.$message.destroy()
this.$message.error(e || '文件上传失败')
}
}
}
</script>