python oss分片上传

208 阅读2分钟

源码Gitee地址:
阿里OSS文档:

阿里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