前端对接阿里OSS

公司最近需要使用阿里OSS上传文件,但是文件类型不固定,开始的想法是通过Java写接口,如果文件过大由后端对文件进行分片处理并上传。在调研过程中发现ali-oss公共模块中提供了分片上传的方法,所以找个工作就交给了前端来做,以减轻后端的压力,于是笔者就开始了漫长的调研过程。

初期考虑只是简单的实现就好,但是为了以后方便维护以及复用情况笔者考虑,使用class进行封装处理。

使用技术栈:

  1. vue-cli 3.0
  2. typescript

依赖:

  1. ali-oss
  2. Element-ui(可忽略)

测试用html结构如下(使用了element-ui)

普通上传 分片上传 停止上传 中断续传

前端直接对接阿里oss需要使用ali-oss公共包,执行一下命令

npm install --save-dev ali-oss

创建文件DockingOSS.ts

class DockingOSS {

}

由于依赖于ali-oss,要考虑到ali-oss在初始化时所需要的参数,封装类时所需要的参数,由于使用typescript就不能再让参数随意填写,而是使用接口对参数进行规范化处理。

interface allOssInterface {
    region:string;  //  地域节点,必填
    accessKeyId:string; //  用户id,必填
    accessKeySecret:string; //  访问密钥,必填
    bucket:string;  //  bucket名称,qjdev-pred-voices
    path?:string;   //  路径,默认为"",用户长传到指定文件夹
    secure?:Boolean;    //  指示OSS客户端使用 HTTPS:true HTTP:false
    parallel?:number;   //  分片数量
    partSize?:number;   //  分片大小
    defaultName?:Boolean;   //  是否使用默认名称
    length?:number; //  随机名称长度
};

对其进行初始化

class DockingOSS {

    //  ali-oss 实例
    private allOSS:any;
    private parallel:number;
    private partSize:number;
    private defaultName:Boolean;
    private path:string;
    private length:number;

    constructor(data:allOssInterface){
        let {region,
            accessKeyId,
            accessKeySecret,
            bucket,
            secure = true,
            parallel = 3,
            partSize = 1024 * 1024,
            defaultName = false,
            path = "",
            length = 50} = data;
        this.partSize = partSize;
        this.parallel = parallel;
        this.defaultName = defaultName;
        this.path = path;
        this.length = length;
        //  实例化ali-oss
        this.allOSS = new AliOss({region,accessKeyId,accessKeySecret,bucket,secure});
    }
    
}

添加普通上传方法,处于考虑到开发者可能需要把文件上传到不同的文件夹,以及会使用随机文件名称或者使用固定文件名称,定义了两个方法用来处理上传路径和文件名称。

class DockingOSS { 

    /**
     * 普通上传
     * file:文件对象
     * _fileName:固定文件名称
     */
    public upload(file:File,_fileName:string = ""):Promise{
        let fileName = _fileName;
        (!fileName) && (fileName = this.getFileName(file));
        const pathName = this.accessPath(fileName);
        return this.allOSS.put(pathName, file)
    }
    
}

添加获取路径和随机名称方法

class DockingOSS { 

    //  获取路径
    private accessPath(fileName:string):string {
        const {path} = this;
        return path?`${path}/${fileName}`:fileName;
    }

    //  获取名称
    private getFileName(file:File):string{
        let {defaultName} = this;
        const fileName:string = file.name;
        if(defaultName) return fileName;
        return this.randomFileName();
    }

    //  随机文件名称
    private randomFileName():string{
        const data = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F",
                        "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
                        "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
                        "s", "t", "u", "v", "w", "x", "y", "z"];
        let nums = "";
        const {length} = this;
        for (let i = 0; i < length; i++) {
            const randomStr:string = (Math.random()*61).toString()
            const r:number = parseInt(randomStr, 10);
            nums += (data[r]).toString();
        }
        return nums;
    }
    
}

添加分片上传上传方法

class DockingOSS { 

    /**
     * 分片上传
     * file:文件对象
     * _fileName:固定文件名称
     * progress:分片上传进度回调函数
     */
    public multipartUpload(file:File, progress:Function,_fileName:string):Promise{
        const {parallel,partSize} = this;
        let fileName = _fileName;
        (!fileName) && (fileName = this.getFileName(file));
        const pathName = this.accessPath(fileName);
        return this.allOSS.multipartUpload(pathName, file, {
            parallel,
            partSize,
            progress
        })
    }
    
}

添加中止上传方法

class DockingOSS { 

    //  中止上传
    public cancel():void{
        this.allOSS.cancel();
    }

}

添加续传方法,由于在续传时需要接收一些参数,需要从中获取到中止上传的文件对象,使用interface对参数进行规范化。

interface checkpointInterface {
    file:File;
    name:string;
    fileSize:number;
    partSize:number;
    uploadId:string;
};

class DockingOSS { 

    /**
     * 分片续传
     * checkpoint:中断上传的文件
     * progress:进度回调函数
     */
    public resume(checkpoint:checkpointInterface, progress:Function):Promise{
        const { uploadId, file } = checkpoint;
        const {parallel,partSize,path} = this;
        return this.allOSS.multipartUpload(uploadId, file, {
            parallel,
            partSize,
            progress,
            checkpoint
        })
    }

}

简易封装就完成了,虽然封装不算太完善但是还是可以满足大部分项目需求的,在应用过程中,可能会很多地方用到该类,可以在类中添加单例,已保证整个项目中只存在一个实例,减少对内存的占用(提高性能从小事开始做起)。

实战应用:



对接阿里oss也是没那么困难的,还是想记录一下,毕竟不用每次都需要翻阅资料了。

需要说明的一点,为什么没有直接使用element-ui的上传组件,为了节省oss空间,以及防止用户误传文件,所以使用这种方式在用户提交数据时,进行文件上传,这样会更好一些。

记录生活分享技术,共同进步共同成长。如果文章中由什么错误,请在评论出提出指正,我会及时做出修改。

你可能感兴趣的:(前端,typescript)