对于文件上传大家都不陌生,基本上都是上传到自己的服务器后再通过服务器上传到阿里oss服务器上,我现在做的项目是需要上传视频的,这个功能其实已经做好了,但是由于视频文件比较大上传到服务器再上传oss的耗时比较长,就要换一种方式从前端直接上传到oss服务器上
传统方式:
Web端常见的上传方法是用户在浏览器或app端上传文件到应用服务器,然后应用服务器再把文件上传到OSS,如下图所示:
上传慢:用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度。
扩展性差:如果后续用户多了,应用服务器会成为瓶颈。
费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器。
直传的方式:
1.直接通过js直传的.但是appid与appkey都暴露在了前端.这样很不安全,最好不要采用,不过可以试着玩玩。
JavaScript客户端签名直传
2.前端向后台请求只去请求获取签名的接口,然后在拿到签名认证后直接向oss服务上传文件,我就是采用的这种方式,因为我并没有用到回调函数,所以就采用这种方式,流程图如下:
服务端请求签名后直传
3.采用服务端签名后直传方案有个问题:大多数情况下,用户上传数据后,应用服务器需要知道用户上传了哪些文件以及文件名;如果上传了图片,还需要知道图片的大小等,为此OSS提供了上传回调方案。流程图如下:服务端签名直传并设置上传回调
(先来看看前端的代码)
我这个项目中用到的layui的,我在他的第三方插件中找到了一个大哥写的组件,并用这个组件实现了我所需的功能,这边附上大哥的博客地址以及我已经下载好了的插件压缩包**插件源码的下载的地址,方便大家使用。
其实这个插件的详细参数说明在文件里都有,因为我也是第一次弄oss直传,弄得详细一点让第一次做这个功能爪哇小伙伴少花费一点时间,我还是贴出来方便大家查看,以下是文件上传js的调用:
aliossUploader.render({
elm:'#uploadBatchFileOther', //上传文件绑定的id
fileType:'video', //文件类型
multiple:false, //是否多文件上传 否
layerArea:['800px','500px'],
layerTitle:'上传文件到阿里云OSS',
policyUrl:ctx+"courseMediaInfo/getOSS", //后台请求签名的路径,换成你们的就行
policyData:{},//请求签名的参数,没有可不写
policyHeader:{
Authorization:layui.data('xxx-data').Authorization //请求签名的headers
},
codeFiled:'code',//请求签名后返回的状态字段
codeStatus:0,//请求签名后返回的状态码值
policyMethod:'GET',//请求签名的方法类型
accessidFiled : 'accessid',//阿里的accessKeyId
policyFiled : 'policy',//签名返回的策略policy(也叫表单域)
signatureFiled : 'signature',//返回的签名(主要就是这个签名)
httpStr:'https',//上传至oss时是否https
region:'oss-cn-hangzhou',//oss的数据中心所在的区域(在你的yml配置文件中可以找到)
bucket: 'xxx-data',//oss的存储空间的名称(你要上传到哪个文件就是哪个名称)
prefixPath:'course/',//上传时的前缀(相当于在你的oss存储空间多一级目录,要提前在你的oss存储空间新建好,要不然上传的时候会报错找不到文件夹)
allUploaded:function(res){//成功回调
// var s = JSON.stringify(res);
// layer.msg(JSON.stringify(res));
// console.log(s[3]);
$view.find("#courseUrl").val(res[0].ossUrl);
/* var var1 = JSON.parse(res).var;*/
},
policyFailed:function(res){//失败回调
layer.msg(JSON.stringify(res));
},
uploadRenderData:{//设置文件大小,还有其他的参数可自行设置(下载源码或者去大哥的博客下看)
size:200000 //单位kb
}
});
提示: 这个地方是上传文件调用所需的,真证用到的源码js在下载插件后的一个叫aliossUploader.js的文件里,可以下载后根据自己的需求自行修改,因为我是采用的这个插件,所以我后台验证签名后返回的格式都是按照所需的参数进行封装的。
需要注意一下的是请求签名返回的参数结构,其实你要关注一下什么是policy以及他的语法,如何生成signature,这样你才能写后台的接口:
{
"code": 0,
"success": true,
"msg": "签名成功",
"data": {
"accessid": "XXXXX",
"host": "http://XXXXX.oss-cn-shanghai.aliyuncs.com",
"policy": "XXXX==",
"signature": "XXXX=",
"expire": 1554851252
}
}
在这里附上链接,因为阿里的文档实在是太分散了,我自己找的时候都找了半天
你写这个小功能就必须了解:
PostObject使用HTML表单上传Object到指定Bucket
Policy 语法结构
以及阿里提供的接口demo我已经下载好了你可以自己去找或者用我的下载好了的都行
public class CourseMediaInfoController extends BaseController {
private final ICourseMediaInfoService courseMediaInfoService;
@Value("${aliyun.oss.endpoint}")
private String endpoint; //这个值你的配置文件中有其实就是 http://oss-cn-hangzhou.aliyuncs.com
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.bucketName.qyjz}")
private String bucketName; //oss存储空间名称
//oss存储课时文件前缀
private String dir = "course/";
@GetMapping("courseMediaInfo/getOSS")
@ResponseBody
//@RequiresPermissions("courseMediaInfo:list")
public Map<String, Object> getOSS() {
HashMap<String, Object> map1 = new HashMap<>();
try{
//开启oss客户端
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime *1000;
Date expiration = new Date(expireEndTime);
//生成的到期时间转换位s,并转换为String
String expire = String.valueOf(expireEndTime / 1000);
PolicyConditions policyConditions = new PolicyConditions();
//构造用户表单域Policy条件
PolicyConditions policyConds = new PolicyConditions();
//设置上传文件大小的范围
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
//设置上传的路径的前缀:就是上传到指定文件夹
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
//根据到期时间生成policy策略
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
//对policy进行UTF-8编码后转base64
byte[] binaryData = postPolicy.getBytes("utf-8");
String endPolicy = BinaryUtil.toBase64String(binaryData);
//生成签名,policy表单域作为填入的值,将该值作为将要签名的字符串。
String signature = ossClient.calculatePostSignature(postPolicy);
//封装参数参数返回
HashMap<String, Object> map = new HashMap<>();
map.put("accessid",accessKeyId);
map.put("host",endpoint);//这里我是直接传过去的,因为在前端访问oss的时候做了拼接的,可以在aliossUploader.js里面找到
map.put("policy",endPolicy);
map.put("signature",signature);
map.put("expire",expire );
map1.put("code",0);
map1.put("success",true);
map1.put("msg","签名成功");
map1.put("data",map);
}catch (Exception e){
e.printStackTrace();
}
return map1;
}
}
这就是后台接口的代码,其实和阿里的demo一摸一样,只是我做了根据插件做了一下修改,添加了注释,因为不加说明我第一眼看上去都不知道这些步骤是干啥的,注意一点的是你的文件上传的前缀要和js那写一致,要不然会报错说你文件夹不存在
1.一定要在阿里的控制台设置post请求跨域,别问我怎么知道的,看下图:
2.注意下前端传过在文件上传时的信息,如果上传除了出了问题可以看下请求体的信息,这就是我前面说到的找不到文件夹的错误,如下图:
更多的错误码阿里有提供的错误码也可以自行百度