OSS前后端分离式上传文件,OSS前端直传

背景

以前我们一直采用:
后端转传 的方式进行文件上传 发现效率很低 且 后端服务器压力较大
现在我们优化成:
前端直传 后端提供token令牌 前端拿到令牌直接访问OSS上传文件效率提高了 且服务器压力也小了

准备工作

1:登录阿里云控制台创建RAM用户
在这里插入图片描述
在这里插入图片描述
及时截图或者复制 AccessKey ID 和 AccessKey Secret
这两项是OSS权限
在这里插入图片描述

这个STS角色访问权限 需要通过这个权限去获取token

在这里插入图片描述
创建角色
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建OSS存储桶

在这里插入图片描述
在这里插入图片描述
取名选择区域按提示完成创建
在这里插入图片描述

开放跨域请求

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

准备工作完毕

建个Spring Boot项目

引入依赖

<!--OSS-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
<!-- JDK9 及以上需要引入下列依赖 应该是8以后移除了很多内容 -->
<dependency>
     <groupId>javax.xml.bind</groupId>
     <artifactId>jaxb-api</artifactId>
     <version>2.3.1</version>
 </dependency>
 <dependency>
     <groupId>javax.activation</groupId>
     <artifactId>activation</artifactId>
     <version>1.1.1</version>
 </dependency>
 <dependency>
     <groupId>org.glassfish.jaxb</groupId>
     <artifactId>jaxb-runtime</artifactId>
     <version>2.3.3</version>
 </dependency>

写个接口应该难不倒你
@RestController
@RequestMapping("/manager/auth")
public class AuthController {

    @Autowired
    private OssService ossService;
    
    @GetMapping(value = "/oss/token")
    //这里的R是我自己封装的统一返回对象 你也可以直接返回JSON啥的
    public R ossToken() {
        return R.data(ossService.token());
    }
}
# 文件上传
OSS:
  # 区域
  endpoint: "https://oss-cn-xxxxx.aliyuncs.com"
  # 密钥
  accessKeyId: "xxxxxxxxxxxxxxxxxxxxxxxx"
  accessKeySecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  # roleArn
  roleArn: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  # 桶
  bucketName: "xxxxxxxxx"
  regionId: "cn-shanghai"
  version: "2015-04-01"
@Data
@Configuration
public class OSSParam {
    @Value("${OSS.endpoint}")
    private String endpoint;
    @Value("${OSS.accessKeyId}")
    private String accessKeyId;
    @Value("${OSS.accessKeySecret}")
    private String accessKeySecret;
    @Value("${OSS.roleArn}")
    private String roleArn;
    @Value("${OSS.bucketName}")
    private String bucketName;
    @Value("${OSS.regionId}")
    private String regionId;
    @Value("${OSS.version}")
    private String version;
}
public interface OssService {
    /**
     * 获取上传文件的token
     * @return
     */
    AssumeRoleResponse token();
    
    /**
     * 批量获取图片连接
     *
     * @param filePathList
     * @return
     */
    Map<String, String> getUrlBatch(Collection<String> filePathList);
}
@Service
public class OssServiceImpl implements OssService {
    /**
     * 自定义的配置参数的类
     */
    @Autowired
    private OSSParam ossParam;
    @Override
    public AssumeRoleResponse token() {
        //随便写 参考下列格式即可 不要有特殊符号
        String roleSessionName = "session_1001";
        //执行角色授权
        IClientProfile profile = DefaultProfile.getProfile(
                //cn-hangzhou 或者 cn-beijing 或者 cn-shanghai 这几个节点都可以 其他的好像不行
                ossParam.getRegionId(),
                //开通账号时下发的两个参数
                ossParam.getAccessKeyId(),
                ossParam.getAccessKeySecret()
        );
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        //version 这里是固定的 2015-04-01
        request.setVersion(ossParam.getVersion());
        //开通角色时 角色信息里的 arn 属性
        request.setRoleArn(ossParam.getRoleArn());
        request.setRoleSessionName(roleSessionName);
        //临时授权有效时间,从 900 到 3600 秒 测试的时候建议写时间给长一点,免得报错都不知道为啥
        request.setDurationSeconds(900L);
        try {
            final AssumeRoleResponse response = client.getAcsResponse(request);
            return response;
        } catch (ClientException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 文件临时访问 URL 获取
     *
     * @param filePathList 后端存储的文件路径
     *                     例如 : web/img/abc.jpg
     *                     其实就是你存储桶里面的文件夹路径
     *                     注意最前面不要带斜杠 例如这样 /web/img/abc.jpg 不要问我为什么 自己去试试就知道了
     * @return 文件夹链接的 key : value 集合 调用方可以直接通过 map.get(filePath) 直接获取对应的链接
     */
    @Override
    public Map<String, String> getUrlBatch(Collection<String> filePathList) {
        //这里 等于 Map<String, String> resultMap = new HashMap<>(); 只是我引用了工具包看起来舒服一点
        Map<String, String> resultMap = Maps.newHashMap();
        if (CollectionUtils.isEmpty(filePathList)) {
            return resultMap;
        }
        //这个token可以用redis存起来过期了再重新生成,效率会高一点
        //过期时间保持一致 或者redis缓存时间稍微短一点,错开那种刚好过期的时间点就好了
        //比如 token 900秒(15分钟)到期,你就设置redis的key 720秒(12分钟)到期,完美错开
        AssumeRoleResponse token = token();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(
                params.getStsEndpoint(),
                token.getCredentials().getAccessKeyId(),
                token.getCredentials().getAccessKeySecret(),
                token.getCredentials().getSecurityToken()
        );
        //过期时间尽量短一点 1-3 分钟即可,
        //只要前端能够显示出来就行了 (时间太长,可能会被人恶意访问造成流量泄露,产生大量费用。切记!!!!)
        //以前小白的时候直接生成10年有效的链接。。。现在看起来是真的虎
        Long expirationTime = System.currentTimeMillis() + params.getStsEffectiveTime();
        Date expirationDate = new Date(expirationTime);
        filePathList.forEach(filePath -> {
            //生成GET请求链接
            URL url = ossClient.generatePresignedUrl(params.getStsBucketName(), filePath, expirationDate);
            resultMap.put(filePath, url.toString());
        });
        return resultMap;
    }
}
用postman点一下看看

在这里插入图片描述
返回一堆东西!说明功夫没白费

来到前端工作

本人是个写后端的 前端没怎么学,但只需要知道大概原理即可
首先去GitHub 下载两个 sdk 文件
在这里插入图片描述

再写个HTML试试水 (建个VUE项目太麻烦 索性就写个HTML玩玩儿)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<form>
			<input id="file" type="file" value="" onchange="getOssClient()" />
			<input id="upload" value="点击上传" type="button" onclick="uploadFile()" />
		</form>
	</head>
	<body>
	</body>
	<!-- 如果你没有前端代码运行工具 直接就写全路径就好了 不出意外的话是个浏览器就能玩 -->
	<script type="text/javascript" src="C:\xxx\xxx\xxx\dist\aliyun-oss-sdk.js"></script>
	<script type="text/javascript" src="C:\xxx\xxx\xxx\dist\aliyun-oss-sdk.min.js"></script>
	<script type="text/javascript">
		var params = {
			accessKeyId: "对应上一步接口返回的 {credentials.accessKeyId}",
			accessKeySecret: "对应上一步接口返回的 {credentials.accessKeySecret}",
			stsToken: "对应上一步接口返回的 {credentials.securityToken}",
			region: "你创建桶的区域 例如:oss-cn-chengdu",
			bucket: "你创建的桶名称"
		}
		function getOssClient() {
			return new OSS({
				...params
			})
		}
		function uploadFile() {
			let client = getOssClient();
			var file = document.getElementById('file').files;
			console.info(file[0].name);
			console.info(client);
			//这里是两个参数  var1 = 你的文件全路径(包括文件名), var2 文件原件
			var rep = client.put("/web_files/test/" + file[0].name, file[0])
			console.info(rep);
		}
	</script>
</html>

好了!试试看,选一个文件,就把这个js文件传上去看看
在这里插入图片描述
发现返回了貌似链接的东西 我们只需要把这个链接传给后端保存起来就OK了
在这里插入图片描述
再去控制台看看到底有没有
在这里插入图片描述

在这里插入图片描述

好了赶紧去点赞收藏吧

  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值