位置: IT常识 - 正文
推荐整理分享前端直传阿里云OSS(阿里前端做什么),希望有所帮助,仅作参考,欢迎阅读内容。
文章相关热门搜索词:前端直传阿里云怎么用,前端直传阿里云怎么用,阿里云前端面试题,阿里云前端外包怎么样,前端项目部署到阿里云服务器,前端直传阿里云怎么用,前端直传阿里云怎么用,前端直传阿里云怎么用,内容如对您有帮助,希望把文章链接给更多的朋友!
阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。
目前通过Web端直传文件(Object)到OSS,有两种方案:
一、利用OSS Browser.js SDK将文件上传到OSS。该方案通过OSS Browser.js SDK直传数据到OSS,支持断点续传,支持各种主流浏览器,可以将File对象、Blob数据以及OSS Buffer上传OSS,该方案还支持下载和删除
二、利用OSS提供的PostObject接口来实现表单上传,不支持断点续传,支持h5,小程序,支持uniapp的uni.uploadFile接口
方案一:使用阿里云SDK上传由于前端环境不安全,为避免暴露阿里云账号访问密钥(AccessKey ID和AccessKey Secret),该方案需要搭建STS服务获取临时访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken),需要先开通STS服务,参考官方文档
后端后端需要导入aliyun-sdk-oss包,用于获取前端需要的key和secret
JDK版本:jdk8
<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>2.0.7</version> <!--<version>3.15.0</version>最新--></dependency>如果是java9及以上版本,则需要添加jaxb相关依赖。添加jaxb相关依赖示例代码如下:
<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><!-- no more than 2.3.3--><dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.3</version></dependency>搭建STS服务(部分代码)
// STS接入地址,例如sts.cn-hangzhou.aliyuncs.com。 @Value("${ramEndpoint}") private String ramEndpoint; // 访问密钥AccessKey ID和AccessKey Secret @Value("${ramAccessKeyId}") private String ramAccessKeyId; @Value("${ramAccessKeySecret}") private String ramAccessKeySecret; // 角色ARN @Value("${ramRoleArn}") // 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest private String ramRoleArn; @Value("${ramRoleSessionName}") private String ramRoleSessionName; private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired RedisTemplate redisTemplate; /** * 通过RAM子账号获取stsToken,作为临时凭据 */ @RequestMapping(value = "getStsToken", method = {RequestMethod.GET, RequestMethod.POST}) public Object getStsToken() { ResponseVo responseVo = new ResponseVo(); AssumeRoleResponse response = null; Object redisToken = null; try { redisToken = redisTemplate.opsForValue().get("stsToken"); } catch (Exception e) { logger.error(e.getMessage()); responseVo.setError(GlobalErrorCode.SYS_RUN_ERROR.getCode()); return responseVo; } if (redisToken != null) { response = JSONObject.parseObject(redisToken.toString(), AssumeRoleResponse.class); responseVo.setSuccess(response); return responseVo; } else { String policy = "{\n" + " \"Version\": \"1\", \n" + " \"Statement\": [\n" + " {\n" + " \"Action\": [\n" + " \"oss:*\"\n" + " ], \n" + " \"Resource\": [\n" + " \"acs:oss:*:*:*\" \n" + " ], \n" + " \"Effect\": \"Allow\"\n" + " }\n" + " ]\n" + "}"; try { DefaultProfile.addEndpoint("", "", "Sts", ramEndpoint); // 构造default profile(参数留空,无需添加region ID) IClientProfile profile = DefaultProfile.getProfile("", ramAccessKeyId, ramAccessKeySecret); // 用profile构造client DefaultAcsClient client = new DefaultAcsClient(profile); final AssumeRoleRequest request = new AssumeRoleRequest(); request.setMethod(MethodType.POST); request.setRoleArn(ramRoleArn); request.setRoleSessionName(ramRoleSessionName); request.setPolicy(policy); // 若policy为空,则用户将获得该角色下所有权限 request.setDurationSeconds(20 * 60L); // 设置凭证有效时间,单位秒 //获取凭证 response = client.getAcsResponse(request); /* * 缓存该凭证,凭证失效后才从OSS再次获取凭证 * 凭证有效时间为20分钟,Redis里只缓存10分钟 */ redisTemplate.opsForValue().set("stsToken", JSONObject.toJSONString(response), 10 * 60, TimeUnit.SECONDS); responseVo.setSuccess(response); return responseVo; } catch (ClientException e) { logger.error(e.getErrMsg()); responseVo.setError(GlobalErrorCode.SYS_RUN_ERROR.getCode()); return responseVo; } } }参考阿里云文档
前端安装
$ npm install ali-oss --save部分代码
onLoad() {this.getStsToken()},methods
/*** @param {String} pathAndName Object完整路径。Object完整路径中不能包含Bucket名称("exampledir/exampleobject.txt")* @param {Object} data (file对象、Blob数据或者OSS Buffer)*/async putObject(pathAndName, data) { try { // 您可以通过自定义文件名(例如exampleobject.txt)或文件完整路径(例如exampledir/exampleobject.txt)的形式实现将数据上传到当前Bucket或Bucket中的指定目录。 const result = await this.getClient().put( pathAndName, data ); console.log('result:', result); } catch (e) { console.log(e); }}, getClient() { if (this.client) { return this.client } const OSS = require('ali-oss'); const client = new OSS({ // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。 region: 'oss-cn-qingdao', // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。 accessKeyId: this.stsToken.credentials.accessKeyId, accessKeySecret: this.stsToken.credentials.accessKeySecret, // 从STS服务获取的安全令牌(SecurityToken)。 stsToken: this.stsToken.credentials.securityToken, refreshSTSToken: async () => { // 向您搭建的STS服务获取临时访问凭证。 let info = await this.$post(GET_STS_TOKEN) info = info.data console.log('-----------refresh--token') return { accessKeyId: info.credentials.accessKeyId, accessKeySecret: info.credentials.accessKeySecret, stsToken: info.credentials.securityToken } }, // 刷新临时访问凭证的时间间隔,单位为毫秒。每隔一段时间定时器会自动掉后台接口刷新token refreshSTSTokenInterval: 600000, // 填写Bucket名称。 bucket: 'zxxxxth-bucket' }); this.client = client return this.client }, getStsToken() { //从后台获取stsToken(改成自己的前端请求接口) this.$post(GET_STS_TOKEN).then(rsp => { if (rsp.success) { this.stsToken = rsp.data; // 初始化一下client让定时任务启动,自动刷新token(避免过期) this.getClient() console.log('this.stsToken:', this.stsToken) } else { uni.showToast({ title: rsp.message, duration: 2000 }); } }) },refreshSTSToken参数说明:当初始化new OSS()时,定时器会启动,当时间到了refreshSTSTokenInterval所设置的值时,并不会立即调用后台接口获取token,只有手动触发put()接口时,才会调用后台接口获取token
参考阿里云文档
开通STS服务步骤
方案二:使用PostObject接口来实现表单上传这个方案支持小程序上传,uniapp上传。无需开通STS服务
后端获取postObject接口需要的policy,OSSAccessKeyId,signature 参考官方文档
这里签名使用后端签名,所以不需要申请开通STS服务
简化版,无回调/** * 利用OSS提供的PostObject接口,通过表单上传的方式将文件上传到OSS。 * 该方案兼容大部分浏览器,但在网络状况不好的时候,如果单个文件上传失败, * 只能重试上传。上传的Object大小不能超过5 GB。 * @return ResponseVo{success:true,message:'',data:{},code:200} */ @RequestMapping(value = "getPostObjectParams", method = {RequestMethod.GET, RequestMethod.POST}) public Object getPostObjectParams() { ResponseVo responseVo = new ResponseVo(); responseVo.setSuccess(OSSServer.getPostObjectParams()); return responseVo; }OSSServer.class
public static OSSClient getOSSClient() {if (null == ossClient) {ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);}return ossClient;}/** * 获取表单上传的方式的PostObject参数 * @return */public static Map<String, Object> getPostObjectParams() {Map<String, Object> respMap = new LinkedHashMap();// 限制参数的生效时间,单位为分钟,默认值为20。int expireTime = 20;// 限制上传文件的大小,单位为MB,默认值为100。int maxSize = 100;// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。// 如果值为"test"那么前端的key参数必须以"test"开头,如test/*、test1.jpg、test/comment/11.jpgString dir = "";// 创建OSSClient实例。OSS ossClient = getOSSClient();try {long expireEndTime = System.currentTimeMillis() + expireTime * 1000 * 60;Date expiration = new Date(expireEndTime);PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize * 1024 * 1024);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);respMap.put("accessKeyId", accessKeyId);respMap.put("policy", encodedPolicy);respMap.put("signature", postSignature);respMap.put("expire", expireEndTime / 1000);} catch (Exception e) {log.error("getPostObjectParams", e);}return respMap;}大多数情况下,用户上传文件后,应用服务器需要知道用户上传了哪些文件以及文件名;如果上传了图片,还需要知道图片的大小等,为此OSS提供了上传回调方案。
流程图:
当用户要上传一个文件到OSS,而且希望将上传的结果返回给应用服务器时,需要设置一个回调函数,将请求告知应用服务器。用户上传完文件后,不会直接得到返回结果,而是先通知应用服务器,再把结果转达给用户。
有回调的PostObject参数/** * 获取表单上传的方式的PostObject参数【有回调】 * @return */public static Map<String, Object> getPostObjectParams() {Map<String, Object> respMap = new LinkedHashMap();// 限制参数的生效时间,单位为分钟,默认值为20。int expireTime = 20;// 限制上传文件的大小,单位为MB,默认值为10。int maxSize = 10;// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。// 如果值为"test"那么前端的key参数必须以"test"开头,如test/*、test1.jpg、test/comment/11.jpg// 可以让用户没有办法上传到其他的目录,从而保证了数据的安全性String dir = "";// 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。String callbackUrl = "https://jmt.xxx.cn/common/postObjectCallBack/";// 创建OSSClient实例。OSS ossClient = getOSSClient();try {long expireEndTime = System.currentTimeMillis() + expireTime * 1000 * 60;Date expiration = new Date(expireEndTime);PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize * 1024 * 1024);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);respMap.put("accessKeyId", accessKeyId);respMap.put("policy", encodedPolicy);respMap.put("signature", postSignature);respMap.put("expire", expireEndTime / 1000);// 配置回调地址JSONObject jasonCallback = new JSONObject();jasonCallback.put("callbackUrl", callbackUrl);//jasonCallback.put("callbackBody",//"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");jasonCallback.put("callbackBody", "{\"filename\":${object},\"mimeType\":${mimeType}}");jasonCallback.put("callbackBodyType", "application/json");//application/x-www-form-urlencodedString base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());respMap.put("callback", base64CallbackBody);} catch (Exception e) {log.error("getPostObjectParams", e);}return respMap;}给oss回调的接口 @RequestMapping(value = "postObjectCallBack", method = RequestMethod.POST) public Object postObjectCallBack(HttpServletRequest request, @RequestBody Object callbackBody) throws IOException { log.info("---callbackBody={}",callbackBody);// "{"filename":"test/comment/tt1.jpg","mimeType":"image/png"}" return callbackBody; }前端小程序const host = '<host>'; //"https://examplebucket.oss-cn-hangzhou.aliyuncs.com"const signature = '<signatureString>';const ossAccessKeyId = '<accessKey>';const policy = '<policyBase64Str>';const key = '<object name>';const securityToken = '<x-oss-security-token>'; const filePath = '<filePath>'; // 待上传文件的文件路径。wx.uploadFile({ url: host, // 这个是阿里云bucket的根地址,使用这个地址拼接路径可以访问已上传的文件。如果是自己服务器则是开发者服务器的URL。 filePath: filePath,// 本地文件路径,小程序chooseImage方法返回的路径 name: 'file', // 必须填file。 formData: { key, policy, OSSAccessKeyId: ossAccessKeyId, signature, // 'x-oss-security-token': securityToken // 使用STS签名时必传。 }, success: (res) => { if (res.statusCode === 204) { console.log('上传成功'); } }, fail: err => { console.log(err); }});uniapp、uView的Upload组件uni.uploadFile({ url: 'https://res.xxx.cn', //这个是阿里云bucket的根地址,使用这个地址拼接路径可以访问已上传的文件 filePath: url,// 本地文件路径,小程序chooseImage方法返回的路径 name: 'file',// 必须填file formData: { key: 'test/comment/tt1.jpg',//会把tt1.jpg图片上传至bucket(上方url所指向)的test/comment目录 policy: this.postObject.policy, OSSAccessKeyId: this.postObject.accessKeyId, signature: this.postObject.signature, // callback: this.postObject.callback }, success: (res) => { console.log('uni.uploadFile success:', res) if(res.statusCode===204){ // 上传成功 console.log('-------------success------------') }else if(res.statusCode===403){ // Policy expired. uni.showToast({ title: '网络超时', duration: 2000 }); // 续期 this.getPostObjectParams() }else{ console.log('上传失败') } // setTimeout(() => { resolve(res) // }, 1000) }, fail(err) { console.error('uni.uploadFile: fail', err) }});onLoad() {this.getPostObjectParams()},...........getPostObjectParams() { //从后台获取stsToken this.$post(GET_POST_OBJECT_PARAMS).then(rsp => { if (rsp.success) { this.postObject = rsp.data; console.log('this.postObject:', this.postObject) } else { uni.showToast({ title: rsp.message, duration: 2000, icon:'none' }); } })},参考官方文档
举一个uniapp例子UI库:uView
<template><!-- 发表评论 --><view class="create-comment"><view class="star comment-common"><view class="title">评分</view><view class="control"><text class="name">游玩体验</text><u-rate :count="5" v-model="starCount" :touchable="false" active-color="#E65526" size="24"></u-rate></view></view><view class="content comment-common"><view class="title">评价内容</view><textarea v-model="resourceComment.content" maxlength="200"placeholder="游玩的满意吗?大家都想了解这里值得去吗?有什么亮点?期待你精彩的点评!"></textarea></view><view class="picture comment-common"><view class="title">图片</view><!-- name=1对应fileList1 --><u-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple :maxCount="15":maxSize="maxSize"></u-upload></view><view class="picture comment-common"><view class="title">视频</view><!-- name=2对应fileList2 --><u-upload :fileList="fileList2" @afterRead="afterRead" @delete="deletePic" name="2" multiple :maxCount="1":maxSize="maxSize" accept="video" uploadIcon="movie"></u-upload></view><button @click="submit()" type="warn" class="submit" :loading="loading" :disabled="loading">发布</button></view></template><script>import {GET_POST_OBJECT_PARAMS} from '../../api/api.js'export default {data() {return {starCount: 0,resourceComment: {content: ''},fileList1: [],fileList2: [],loading: false,postObject: {expire: 0},maxSize: 100 * 1024 * 1024}},onLoad() {},methods: {// -----upload start// 新增图片async afterRead(event) {console.log('event:', event)// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式let lists = [].concat(event.file)// console.log('lists:', lists)let fileListLen = this[`fileList${event.name}`].length// console.log('fileListLen:', fileListLen)lists.map((item) => {this[`fileList${event.name}`].push({...item,status: 'uploading',message: '上传中'})})let time = new Date().getTime() / 1000// console.log('time:', time)if (time > this.postObject.expire) {// policy过期,续期await this.getPostObjectParams()}for (let i = 0; i < lists.length; i++) {const result = await this.uploadFilePromise(lists[i].url)let item = this[`fileList${event.name}`][fileListLen]this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {status: result ? 'success' : 'failed',message: '',url: result}))fileListLen++}},compressJpgImage(src) {return new Promise((resolve, reject) => {// uni.compressImage({// src: src,// quality: 80,// success: res => {// console.log(res.tempFilePath)// }// })})},uploadFilePromise(url) {return new Promise((resolve, reject) => {let a = uni.uploadFile({url: 'https://res.xxxx.cn',filePath: url,name: 'file', // 必须填fileformData: {key: 'test/comment/tt3.jpg',policy: this.postObject.policy,OSSAccessKeyId: this.postObject.accessKeyId,signature: this.postObject.signature,callback: this.postObject.callback},success: (res) => {// 未配置回调 上传成功返回 {date:"",errMsg:"uploadFile:ok",statusCode:204},如果配置了回调data参数才会有值// 配置了回调 上传成功返回 {{data:{"filename":"test/comment/tt1.jpg","mimeType":"image/png"},errMsg:"uploadFile:ok",statusCode:200}console.log('uni.uploadFile success():', res)if (res.statusCode === 204 || res.statusCode === 200) {// 上传成功console.log('-------------uploaded success')resolve(url)} else {console.log('-------------uploaded failed')uni.showToast({title: '上传失败',duration: 2000,icon: 'error'});resolve()}},fail(err) {console.error('uni.uploadFile: fail():', err)}});})},// 删除图片deletePic(event) {this[`fileList${event.name}`].splice(event.index, 1)},// -----upload endgetPostObjectParams() {//从后台获取postObjectreturn this.$post(GET_POST_OBJECT_PARAMS,{folderType:'comment'}).then(rsp => {// this.postObject = rspif (rsp.success) {this.postObject = rsp.data;console.log('this.postObject:', this.postObject)} else {console.error('getPostObjectParams:', rsp.message || '系统错误')}})}}}</script><style lang="scss">.create-comment {padding: 12px;.comment-common {margin-bottom: 10px;padding: 15px 10px;background-color: white;border-radius: 10px;}.title {margin-bottom: 10px;font-size: 16px;font-weight: bold;}.star {.control {display: flex;align-items: center;.name {margin-right: 10px;}}}.content {textarea {font-size: 14px;width: 100%;}}.picture {}.submit {margin-top: 20px;width: 80%;font-size: 15px;color: white;background-color: #e65526;}}</style>附:根据blob链接获取blob对象
/** * 根据blob链接获取blob对象 * @param {Object} url "blob:http://localhost:8085/d688ce4f-0f5d-418c-85ad-62bcb3f38dee" * @returns Blob(31846) {size: 31846, type: "image/jpeg"} */getBlobByUrl(url) {return uni.request({url: url,// 合法值:text、arraybufferresponseType: 'arraybuffer'}).then(data=>{const [error, rsp] = data;if(error){console.error(`post-error:${error}, url:${url}`)return {message: error.errMsg}}else{let buffer = rsp.data// ArrayBuffer(185) {}console.log('buffer:', buffer)return new Blob([buffer])}})// return new Promise((resolve, reject) => {// let xhr = new XMLHttpRequest()// xhr.open('GET', url, true)// xhr.responseType = 'blob'// xhr.onload = function(e) {// if (this.status == 200) {// let myBlob = this.response// // let file = new window.File(// // [myBlob],// // 'myfile.jpg', {// // type: myBlob.type// // }// // )// // console.log("files:", file)// resolve(myBlob)// } else {// reject(false)// }// }// xhr.send()// })},blobUrl、blob、base64、file相互转化:https://www.cnblogs.com/jing-zhe/p/15402775.html
uniapp选择file
<button @click="submit()" type="warn" class="submit" :loading="loading" :disabled="loading">发布</button>submit() { let utils = new Utils() uni.chooseImage({ count: 6, //默认9 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 sourceType: ['album'], //从相册选择 success: function(res) { console.log(JSON.stringify(res.tempFilePaths)); console.log(res.tempFiles) utils.getFileMD5(res.tempFiles[0], function(md5) { console.log('md5:', md5) }) } });},上一篇:鸟瞰蒙特雷附近的大苏尔海岸线,加利福尼亚州 (© Blue Planet Archive/Alamy)(蒙特雷景点)
下一篇:小刺猬 (© lorenzo104/Getty Images)
友情链接: 武汉网站建设