前言
最近搞了两天的腾讯云cos服务器上传图片,在网上查了很多文章,大部分都是说的纯前端、纯后端或者是其他语言直传cos,很少有使用后端java生成预签名url,前端element-ui再进行直传cos的文章。使用这种方案既解决了纯前端直传可能会造成密钥泄露的问题,也解决了后端上传cos影响性能的问题。
一、注册腾讯云获取密钥
具体注册流程网上文章很多,自己找找就好了,很简单的。
二、后端生成签名url
1.导入依赖
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.54</version>
</dependency>
如果导入依赖报错,可以去官网的 ‘产品文档’ 更新最新的依赖:
2.创建controller
代码如下:
package top.itimmortal.edu.controller;
@RestController
@RequestMapping("/oss")
public class SignDemo { //文件名自行修改
@GetMapping("/sign")
public static JSONResult generateCosSignature() {
// 1 初始化
COSCredentials cred = new BasicCOSCredentials("你的SecretId", "你的SecretKey");
// 2 设置的所属地域:我的是https://itimmortal-1319957111.cos.ap-chengdu.myqcloud.com
ClientConfig clientConfig = new ClientConfig();
Region region = new Region("ap-chengdu"); //更换为你的所属地域,我这里是成都的
clientConfig.setRegion(region);
// 3 生成 cos 客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// 你存储桶名称
String bucketName = "itimmortal-1319957111";
//对象键(Key),使用UUID生成不重复的随机数,然后拼接文件后缀组成你前端上传到cos中的文件名
String key = UUID.randomUUID() + ".jpeg"; //33585111-093d-4502-a5ef-d5405ee19f2e.jpeg
//签名过期时间
Date expirationTime = new Date(System.currentTimeMillis() + 30 * 60 * 1000);
// 生成预签名上传 URL
//示例:https://itimmortal-1319957351.cos.ap-chengdu.myqcloud.com/0d3326e5-2272-4ee0-8445-e0ef5eec98fc.jpeg?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDxu111Pr9GBvUs1111lLm3Dj7PUBjIuXS%26q-sign-time%3D1691402050%3B1691111850%26q-key-time%3D169141150%3B169140111%26q-header-list%3Dhost%26q-url-param-list%3D%26q-signature%3D7d833d12f6e1668e260fa56edd0037f112e68111
URL url = cosclient.generatePresignedUrl(bucketName, key, expirationTime, HttpMethodName.PUT, new HashMap<>(), new HashMap<>());
//返回json格式给后端
return JSONResult.success(url);
}
}
其实在官网也有,https://cloud.tencent.com/document/product/436/35217
,我也是在总结博客去的时候才突然看到的,一直没看到…
三. 前端代码
使用element-ui的el-upload
组件,可以在官网copy下来进行修改:
<el-form-item prop="logo" style="width: 400px">
<!--
action:上传的地址,
auto-upload:是否在选取文件后立即进行上传,
http-request:自定义上传的实现,
before-upload:上传文件之前的钩子
-->
<el-upload
class="upload-demo"
action="https://itimmortal-1319957111.cos.ap-chengdu.myqcloud.com"
:auto-upload="true"
:http-request="uploadImage"
:before-upload="beforePicUpload"
:limit="1">
<el-button size="small" type="primary" icon="el-icon-picture-outline">上传封面</el-button>
<span slot="tip" class="el-upload__tip">支持500kb,格式jpg</span>
</el-upload>
</el-form-item>
接下来写before-upload
:上传文件之前的钩子:
async beforePicUpload() {
await this.getSign();
},
async getSign() {
//让这个请求变成同步请求
await this.$http.get("/common/oss/sign").then(response => {
//接收预签名url链接
this.uploadUrl = response.data.data; //或者 response.data
});
},
比较复杂的就是http-request
:自定义上传的实现了,我其实也不怎么会前端,所以有些参数也看不懂:
//自定义上传
uploadImage: function (file) {
// 这里的`file`参数是要上传的文件对象
// 在这里根据需要添加一些逻辑,如显示进度条
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
//element-ui默认使用post提交,但是我们生成的url需要使用 put 提交
//需要指定 put 直传,以及this.uploadUrl(后端返回的url)
xhr.open('PUT', this.uploadUrl, true);
//设置上传文件的类型
xhr.setRequestHeader('Content-Type', file.file.type); // 或者 file.type
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
//进入到这里就表明上传成功了
//我这里对后端返回的url进行截取方便存入数据库,因为前端还需要展示图片
let indexOf = this.uploadUrl.indexOf("?");
this.addForm.pic = this.uploadUrl.slice(0,indexOf);
} else {
reject(xhr.statusText);
}
}
};
xhr.onerror = () => {
reject(xhr.statusText);
};
//发送
xhr.send(file.file); //或者 file
});
},
上传成功后就能在腾讯云cos服务器上看得到了。
总结
其实看看就行了,我也只是完成前端直传cos的功能,也仅仅只是完成功能而已,只是作为学习使用,分享一下。