阿里云oss大文件上传解决方案

文件上传实现的效果

概述

什么是文件上传?:

文件上传,是指将本地图片、视频、音频等文件上传到服务器上,在开发Web应用程序时,文件上传、下载和删除是常见的功能之一。
文件上传常用方案:

  1. 直接将图片保存到服务的硬盘(springmvc中的文件上传)
  2. 使用第三方的存储服务(例如OSS)
    因为 第三方OSS 开发简单,拥有强大功能,免维护,这些优点 企业中一般使用第三方的存储服务。
    最好的做法就是上传前从后端获取临时上传凭证,然后前端自行上传。如果把文件上传到后端再上传到对象存储这些地方也不行,即使分片也会比较慢,因为服务端比较耗时,而且还会占用服务器带宽。这些问题自己踩了一波大坑。下面是我分片后经过后端得到时间 服务器5M带宽,分片大小1M。可以看到这个是非常慢的严重影响用户体验。所以我们要采取前端直接传输到oss这种方案 。
    服务器分片上传
    下面将讲解上传前从后端获取临时上传凭证,然后前端自行上传这种方案的实现步骤

一、使用 npm 安装SDK开发包

npm install ali-oss

二、VUE相关代码

1.vue上传组件

关闭自动上传,将action的链接置空,样式这些可以自定义

<div class="itemUpload">

                <div>
                    <el-upload
                          ref="upload"
                          drag
                          action="#"
                          :on-change="uploadFile"
                          :auto-upload="false"
                    >
                        <i class="el-icon-upload"></i>
                        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                    </el-upload>
                    <el-progress
                            style="margin: 20px 0"
                            :text-inside="true"
                            :stroke-width="26"
                            :percentage="progress"
                    ></el-progress>
                </div>

            </div>

2.data中定义数据

进度条相关配置

data(){
      return{
      	progress: 0
      }
}

3.使用到的方法uploadFile

上传文件如果我们想修改文件名 网上好多说直接在 client.multipartUpload 方法中修改 经过测试是不行的,不知道我是不是哪里搞错了 ,最终我的解决方式是先复制一份文件 修改文件名字后 ,然后在上传这样不会报错

    methods: {

        async uploadFile(files,fileList) {
            let that = this;
            that.progress = 0;
            let file1 = files.raw;
            if (fileList.length > 1) {
                fileList.splice(0, 1);
            }
            this.fileListDate = fileList;
            var fileExtension = file1.name.substring(file1.name.lastIndexOf('.') + 1);
            var name = that.priceDetails.fileName + '.' + fileExtension;

            let number = Date.parse(new Date());
            var split = '/';
            var folder = split+that.userInfo.id + split + number + split;
            //这里是复制文件 然后修改文件名   例子:/a/c/c.img  保存后在阿里云 这个文件夹
             let file = new File([file1],folder+name,{type:file1.type});
            console.log("文件信息")
            console.log(file)
            let OSS = require("ali-oss");
            let res = await getFileConfig();//向后端发请求获取信息
            let client = new OSS({
                bucket: "abc",//上传的文件夹
                region: "oss-cn-beijing",
                accessKeyId: res.data.data.accessKeyId,
                accessKeySecret: res.data.data.accessKeySecret,
                stsToken: res.data.data.securityToken,
                expiration: res.data.data.expiration,
            });
            const options = {

                // 获取分片上传进度、断点和返回值。
                progress: (p, cpt, res) => {
                       console.log(p)
                    if(p == 1){
                        console.log("上传完成")
                        that.progressWord = '上传完成';
                    }
                    that.progress = Number((p * 100).toFixed(0));//进度条
                },
                // 设置并发上传的分片数量。
                parallel: 9999,
                // 设置分片大小。默认值为1 MB,最小值为100 KB。
                partSize: 1024 * 1024,
                timeout: 180000,//设置超时时间
                // headers,
                // 自定义元数据,通过HeadObject接口可以获取Object的元数据。
                // meta: { year: 2020, people: "test" },
                // ,
                // callback: {
                //     // 设置回调请求的服务器地址,且要求必须为公网地址。
                //     url: this.baseUrl + "/file/config",
                //     // 设置发起回调时请求body的值。
                //     // body: res.data.body.callback.body,
                //     // // 设置发起回调请求的Content-Type。
                //     // contentType: res.data.body.callback.contentType,
                // },
            };

            async function multipartUpload() {
                console.log("开始分片上传")
                console.log(res)
                var fileExtension = file.name.substring(file.name.lastIndexOf('.') + 1);
                var name = that.priceDetails.fileName + '.' + fileExtension;
                // let number = Date.parse(new Date());
                // var split = '/';
                // var folder = split+that.userInfo.id + split + number + split;
                console.log("folder")
                console.log(folder)
                name = name.trim();

                var fileName = folder+file.name;
                try {
                     //object-name可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当                前Bucket或Bucket下的指定目录。经过测试如何前面加上文件夹 上传会出现NoSuchKey错误 所以我前面增加复制文件代码
                    let result = await client.multipartUpload(
                        file.name,
                        file,
                        {
                            ...options,
                        }
                    );
                    console.log("返回结果");
                    console.log(result);
                    let head = await client.head(file.name);
                    console.log(result.res.requestUrls);
                    var url = result.res.requestUrls[0];
                    console.log("文件地址")
                    console.log(url)
                    //可以处理自己的业务todo
             
                } catch (e) {
                    // 捕获超时异常。
                    console.log("上传异常");
                    that.progress = 0;
                    console.log(e);
                }
            }
            multipartUpload(); //调用函数
        }
}

二、Java相关代码

获取临时的密钥

我们需要在阿里云建立sts账户,配置相关信息

  @RequestMapping("/sts")
    public AjaxResult sts(HttpServletRequest req) {
        AssumeRoleResponse.Credentials credentials = null;
       // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
        String endpoint = "sts.cn-beijing.aliyuncs.com";
       // 新建的sts的accessKeyId   accessKeySecret 
        String accessKeyId = "";
        String accessKeySecret = "";

        //    需要授权的角色名称
        String roleArn = "acs:ram::31124757:role/aliyunoss-role";
        String roleSessionName = "alice";

//    修改 Resource  abc 为自己的桶的名字
        String policy = "{\n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:GetObject\",\n" +
                "                \"oss:PutObject\",\n" +
                "                \"oss:DeleteObject\",\n" +
                "                \"oss:ListParts\",\n" +
                "                \"oss:AbortMultipartUpload\",\n" +
                "                \"oss:ListObjects\"\n" +
                "            ],\n" +
                "            \"Effect\": \"Allow\",\n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:abc/*\",\n" +
                "                \"acs:oss:*:*:abc\"\n" +
                "            ]\n" +
                "        }\n" +
                "    ],\n" +
                "    \"Version\": \"1\"\n" +
                "}";
        try {
            // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
            DefaultProfile.addEndpoint("", "", "Sts", endpoint);
            // 构造default profile(参数留空,无需添加region ID)
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy); // Optional
            request.setProtocol(ProtocolType.HTTPS); // 必须使用HTTPS协议访问STS服务);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            credentials = response.getCredentials();
        } catch (ClientException e) {
        } catch (ServerException e) {
            throw new RuntimeException(e);
        } catch (com.aliyuncs.exceptions.ClientException e) {
            throw new RuntimeException(e);
        }
        return success(credentials);

    }

总结

可能遇见的问题 :

  1. 权限不足 这个需要配置sts 的相关权限
  2. 前端跨域

oss配置跨域
亲测可用,有使用问题或者出错的地方,欢迎大家留言

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值