阿里OSS 有相对应的SDK,使用起来更加方便。
前端核心代码
async handleUpload (fileObj) {
let file = fileObj.file
let filename = file.name
try {
// 如果文件小于5MB,直接上传
if (file.size < 5 * 1024 * 1024) {
let formData = new FormData();
for (let key in data) {
formData.append(key, data[key]);
}
formData.append("file", file);
return
} else {
// 如果文件大于等于5MB,分片上传
// 1、创建分片请求
let uploadId = await this.createInit(filename)
console.log(uploadId)
// 2、上传分片数据
let data = {
fileName: filename,
file: file,
uploadId: uploadId
}
let partResult = await this.uploadByPieces(data)
console.log(partResult)
// 3、合并分片请求
let comData = {
key: filename,
upload_id: uploadId,
parts: partResult
}
let comResult = this.complete_multipart_upload(comData)
this.$message.success('合并成功')
}
} catch (e) {
console.error(e)
}
},
// 创建分片请求
async createInit (key) {
return new Promise((resolve, reject) => {
axios({
url: 'http://127.0.0.1:5000/init_multipart_upload?key=' + key,
method: "post",
data: {
key
}
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
},
// 上传分片
async uploadByPieces ({ fileName, file, uploadId }) {
// 上传过程中用到的变量
const chunkSize = 5 * 1024 * 1024; // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize); // 总片数
// 获取当前chunk数据
const getChunkInfo = (file, index) => {
let start = index * chunkSize;
let end = Math.min(file.size, start + chunkSize);
let chunk = file.slice(start, end);
return { start, end, chunk };
};
// 分片上传接口
const uploadChunk = (data, index) => {
return new Promise((resolve, reject) => {
axios({
url: 'http://127.0.0.1:5000/upload_part',
method: "post",
data,
params: {
key: fileName,
uploadId: uploadId,
part_number: index
},
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
}
// 针对单个文件进行chunk上传
const readChunk = (index) => {
const { chunk } = getChunkInfo(file, index);
let fetchForm = new FormData();
fetchForm.append("chunk", chunk);
fetchForm.append("file", chunk);
fetchForm.append("index", index + 1);
fetchForm.append("chunkCount", chunkCount);
return uploadChunk(fetchForm, index + 1)
};
// 针对每个文件进行chunk处理
const promiseList = []
try {
for (let index = 0; index < chunkCount; ++index) {
promiseList.push(readChunk(index))
}
const res = await Promise.all(promiseList)
return res
} catch (e) {
return e
}
},
// 合并请求
async complete_multipart_upload (data) {
return new Promise((resolve, reject) => {
axios({
url: 'http://127.0.0.1:5000/complete_multipart_upload',
method: "post",
data
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
}
后端核心代码
@app.route("/init_multipart_upload", methods=['POST'])
def init_multipart_upload():
key = request.values.get("key")
# 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
auth = oss2.Auth('AccessKey', 'AccessSE')
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-shenzhen.aliyuncs.com', 'weiju-msg')
upload_id = bucket.init_multipart_upload(key).upload_id
return upload_id, 200
@app.route("/upload_part", methods=['POST'])
def upload_part():
key = request.values.get("key")
upload_id = request.values.get("uploadId")
part_number = request.values.get("part_number")
uploaded_file = request.files['file']
# 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
auth = oss2.Auth('AccessKey', 'AccessSE')
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-shenzhen.aliyuncs.com', 'weiju-msg')
result = bucket.upload_part(key, upload_id, part_number, uploaded_file)
print('上传完成', result)
info = dict()
info['part_number'] = part_number
info['etag'] = result.etag
return jsonify(info), 200
@app.route("/complete_multipart_upload", methods=['POST'])
def complete_multipart_upload():
key = request.json['key']
upload_id = request.json['upload_id']
parts = request.json['parts']
parts_info_array = []
for item in parts:
parts_info_array.append(PartInfo(item["part_number"], item["etag"]))
# 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
auth = oss2.Auth('AccessKey', 'AccessSe')
# Endpoint以杭州为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-shenzhen.aliyuncs.com', 'weiju-msg')
# 完成分片上传。
# 如需在完成分片上传时设置相关Headers,请参考如下示例代码。
headers = dict()
# 设置文件访问权限ACL。此处设置为OBJECT_ACL_PRIVATE,表示私有权限。
headers["x-oss-object-acl"] = oss2.OBJECT_ACL_DEFAULT
bucket.complete_multipart_upload(key, upload_id, parts_info_array, headers=headers)
return "合并成功", 200