VUE+EmelentUI实现-OSS前端直传后端签名

Web端上传介绍

本文介绍如何通过Web端直传文件(Object)到OSS。---------------阿里云文档

背景信息

Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传到OSS。具体流程如下图所示。时序图

和数据直传到OSS相比,以上方法存在以下缺点:

  • 上传慢:用户数据需先上传到应用服务器,之后再上传到OSS,网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度。
  • 扩展性差:如果后续用户数量逐渐增加,则应用服务器会成为瓶颈。
  • 费用高:需要准备多台应用服务器。由于OSS上行流量是免费的,如果数据直传到OSS,将节省多台应用服务器的费用。

技术方案

目前通过Web端将文件上传到OSS,有以下三种方案:

  • 利用OSS Browser.js SDK将文件上传到OSS

    该方案通过OSS Browser.js SDK直传数据到OSS,详细的SDK Demo请参见上传文件。在网络条件不好的状况下可以通过断点续传的方式上传大文件。该方案在个别浏览器上有兼容性问题,目前兼容IE10及以上版本浏览器,主流版本的Edge、Chrome、Firefox、Safari浏览器,以及大部分的Android、iOS、WindowsPhone手机上的浏览器。----安全性差

  • 使用表单上传方式将文件上传到OSS

    利用OSS提供的PostObject接口,通过表单上传的方式将文件上传到OSS。该方案兼容大部分浏览器,但在网络状况不好的时候,如果单个文件上传失败,只能重试上传。操作方法请参见PostObject上传方案

  • 通过小程序上传文件到OSS

    通过小程序,如微信小程序和支付宝小程序,利用OSS提供的PostObject接口来实现表单上传。操作方式请参见微信小程序直传实践支付宝小程序直传实践

Web端向服务端请求签名,然后直接上传,不会对服务端产生压力,而且安全可靠。但本示例中的服务端无法实时了解用户上传了多少文件,上传了什么文件。如果想实时了解用户上传了什么文件,可以采用服务端签名直传并设置上传回调(本地无法实现回调,oss回调需要服务器能被外网访问)。

在这里插入图片描述
流程介绍

  1. Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)
  2. 应用服务器返回相关参数
  3. Web前端直接向OSS服务发起上传文件请求
  4. 等上传完成后OSS服务会回调应用服务器的回调接口(不实现)
  5. 应用服务器返回响应给OSS服务(不实现)
  6. OSS服务将应用服务器回调接口的内容返回给Web前端

后端签名实现

在Controller中写一个Mapping借口,实现前端对签名的访问

@RestController
public class OSSController {

    @CrossOrigin //加上此注解实现跨域
    @RequestMapping("/oss/policy")
    public Map<String, String> policy() {
        System.err.println("被请求了!");
        String accessId = "LTAI5t8duBoMwvobqscKSLEU"; // 请填写您的AccessKeyId。
        String accessKey = "0avav5Ha0sgvVyEThgIxSufZbRb9uk"; // 请填写您的AccessKeySecret。
        String endpoint = "oss-cn-shanghai.aliyuncs.com"; // 请填写您的 endpoint。
        String bucket = "my-tuling-oss"; // 请填写您的 bucketname 。
        String host = "https://" + bucket + "." + endpoint; // host的格式为 BucketName.endpoint

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String date = simpleDateFormat.format(new Date());

        String dir = "前端直传测试/" + date + "/"; // 用户上传文件时指定的前缀。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);


            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<String, String>();
            //阿里云oss前端直传必须参数
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));
            return respMap;
        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return null;
    }
}

此方法在阿里云的开发文档中可以找到—[传送门](Java (aliyun.com))

我们只需要进行简单的修改自己所需的必要参数即可

启动项目访问测试:eg:http://localhost:8088/oss/policy
在这里插入图片描述

VUE+ElementUI实现前端直传

1、设置阿里云Bucket的跨域规则

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、创建前端项目(假设已经懂得VUE,自己用ajax也可以)

1、初始化vue项目

1、提前将Vscode、nodejs等安装好。

2、全局安装vue-cli,vue-cli可以帮助我们快速构建Vue项目。

vscode终端安装命令:

npm install -g vue-cli

3、安装webpack,它是打包js的工具

安装命令:

npm install -g webpack

4、创建vue项目

首先创建一个文件夹用来存放你的项目,用vscode打开对应的文件夹,并在终端cd到对应的文件夹。比如我的文件夹就是myvue

创建命令:

vue init webpack myvue(这是你的项目名称)

接着会出现一些配置项,可以根据需要配置,也可以默认,直接按回车。
在这里插入图片描述
然后继续等待安装依赖项。完成之后,一个基本的 vue项目就搭建完了。完成之后的vscode左边可以看到如下目录,其中main.js就是入口。
在这里插入图片描述
5、运行项目:在终端目录为当前项目目录情况下输入以下命令

npm run dev

终端输出:
在这里插入图片描述
浏览器访问红色框中链接即可

6、题外话:项目打包发布上线

输入命令:

npm run build

完成之后,项目文件夹中会出现一个dist文件夹,里面就是打包之后的内容,直接部署就好了。

2、安装ElementUI(2.15.7版本)

官方文档:https://element.eleme.cn/#/zh-CN/
1、安装:

npm i element-ui -S

2、在项目src\components下建立组件:ossUpload.vue

/*
ElementUI上传组件版本:2.15.7
url:https://element.eleme.cn/#/zh-CN/component/upload
*/
<template>
    <!--  -->
    <el-upload
        class="upload-demo"
        :action="objData.host"
        :file-list="fileList"
        :data="objData"
        :before-upload="ossPolicy"
        list-type="picture"
    >
        <el-button size="small" type="primary">点击上传</el-button>
        <div slot="tip" class="el-upload__tip">
            只能上传jpg/png文件,且不超过500kb
        </div>
    </el-upload>
</template>
<script>
import axios from 'axios'
export default {
    data () {
        return {
            fileList: [
                {
                    name: 'food.jpeg',
                    url:                        'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
                },
                {
                    name: 'food2.jpeg',
                    url:                 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
                }
            ],
            objData: {
                OSSAccessKeyId: '',
                policy: '',
                Signature: '',
                key: '',
                host: '',
                dir: ''
            }
        }
    },
    methods: {
        ossPolicy (file) {
            alert('before-upload开始执行')
            let _self = this
            // return false直接停止上传
            // 在上传之前进行服务器签名
            return new Promise((resolve, reject) => {
                // 请求后端(请求地址和后端访问地址一样)
                axios
                    .get('http://localhost:8090/oss/policy')
                    .then(response => {
                        alert(JSON.stringify(response.data))
                        //获取前端参数
                        _self.objData.OSSAccessKeyId = response.data.accessid
                        _self.objData.policy = response.data.policy
                        _self.objData.Signature = response.data.signature
                        _self.objData.dir = response.data.dir
                        _self.objData.host = response.data.host
                        // eslint-disable-next-line no-template-curly-in-string
                        _self.objData.key = response.data.dir + '${filename}'
                        resolve(true) // 继续上传
                    })
                    .catch(function (error) {
                        alert(error)
                        console.log(error)
                        // reject(false)
                        reject(new Error(false)) // 停止上传
                    })
            })
        }
    }
}
</script>
<style></style>

3、在项目中的HelloWorld.vue中使用ossUpload.vue组件

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>Essential Links</h2>
        <ul>
            <li>
                <a href="https://vuejs.org" target="_blank"> Core Docs </a>
            </li>
            <li>
                <a href="https://forum.vuejs.org" target="_blank"> Forum </a>
            </li>
            <li>
                <a href="https://chat.vuejs.org" target="_blank">
                    Community Chat
                </a>
            </li>
            <li>
                <a href="https://twitter.com/vuejs" target="_blank">
                    Twitter
                </a>
            </li>
            <br />
            <li>
                <a
                    href="http://vuejs-templates.github.io/webpack/"
                    target="_blank"
                >
                    Docs for This Template
                </a>
            </li>
        </ul>
        <h2>Ecosystem</h2>
        <ul>
            <li>
                <a href="http://router.vuejs.org/" target="_blank">
                    vue-router
                </a>
            </li>
            <li>
                <a href="http://vuex.vuejs.org/" target="_blank"> vuex </a>
            </li>
            <li>
                <a href="http://vue-loader.vuejs.org/" target="_blank">
                    vue-loader
                </a>
            </li>
            <li>
                <a href="https://github.com/vuejs/awesome-vue" target="_blank">
                    awesome-vue
                </a>
            </li>
        </ul>
        <!-- 使用上传模板组件 -->
        <ul>
            <li>
                <OssUpload></OssUpload>
            </li>
        </ul>
    </div>
</template>

<script>
// 导入上传组件
import OssUpload from '@/components/ossUpload'
// import OssUpload from './ossUpload.vue';
export default {
    name: 'HelloWorld',
    components: { OssUpload },
    data () {
        return {
            msg: 'Welcome to Your Vue.js App'
        }
    }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1,
h2 {
    font-weight: normal;
}
ul {
    list-style-type: none;
    padding: 0;
}
li {
    display: inline-block;
    margin: 0 10px;
}
a {
    color: #42b983;
}
</style>

4、运行后端程序,运行前端程序

前端上传图片后:
在这里插入图片描述
后端控制台输出:
在这里插入图片描述
5、查看oss是否上传成功(我这里用的是oss browser查看的,和浏览器登录阿里云查看一样)

目录生成
在这里插入图片描述
图片如下
在这里插入图片描述
上传成功!

Logo

前往低代码交流专区

更多推荐