小程序阿里云oss前端直传

前言

按照我以前的风格,现在这篇文章也是,在网上找到各个版本的代码,发现无法使用。小程序作为当前最热门的模块,开发bug当然也不在少数,其中上传文件,也不单单依赖于后端。我使用的是阿里云oss,方法是前端直传,首先更正一下,OSS的API并不支持小程序前端直传。
当前各个IT网站交流,贴子的地方,都有很多案例,就不一一贴出来了

一、开发配置

Hbuilder软件的uniapp项目,后端java

二、百度之后一系列开发问题

1、内容冗长不清楚写的什么

各式各样的代码通篇无注释,也不知道写的什么东西(这种人真的不想说。。。估计又是从哪儿扒的)

2、搞清楚前端 “直传”

说是前端直传,要么用的框架,什么element,vant,要么用的组件选的本地文件,然后结果还是把文件路径传给后台而已,其实和本地传文件一点关系都没有。

3、代码运行环境,这个问题就要多说了

百度的时候,各种html,web,或者是vue-element,或者是react。或者是说了,只管传图片的。说真的,到处都是只有图片,没有音频,视屏的方法。
在者杀人猪心,自己封装的另外的代码,不放出来么,就给一个ui界面的div代码。

查了诸多资料,显示,小程序只传,与其他平台不太一样,如果直接授权accessKeyId,和accessKeySecret ,Bukyet并不会成功。

并且oss上传,需要的是一个文件流,而不是feil文件,而流文件需要插件

4、官访文档错误

我在根据oss文档写的时候,发现他们没有提供js插件的下载出处,所以有了bug,无法使用

三、可行方案

1、比较重要的,根据官方文档,直接授权是否可行。

在另一个app项目中,创建oss实例,只需要给出region,accessKeyId,accessKeySecret以及bucket。就可以授权成功,前端直传。
但是小程序并不是这样的,忘记在哪儿看的。意思是,因为小程序没有主体,前端授权密钥风险很大,所以必须设置你的OSS,bucket为公开状态,也是就是其他人也可以进行公共的读写,存储。当然,用户的数据不可能直接暴露。所以pass

所以根据oss文档 微信小程序直传实践 需要STS签名服务,才可以对oss进行直传操作
文档中
步骤1:配置Bucket跨域访问
步骤2:微信小程序配置域名白名单 都没有问题,跟着设置就行,出问题的是 步骤三

为了您的数据安全,建议使用签名方式上传文件。OSS提供以下两种签名方式的代码:

呵呵 ,说白了说就是,不用STS签名我就不建议你用了
————因为我们没有建议不使用STS签名的方法(微笑脸)

2、重头来了

步骤三
分为服务端签名:(使用服务端签名时,您需要先搭建一个签名服务,之后由客户端调用签名服务生成签名。)
客户端签名:(使用客户端签名时,您需要先在服务端搭建一个STS服务,之后由客户端获取STS临时授权账号并生成签名。)
?????????????????
说白了 还是都需要在后端搭建,那我为什么不选择一个简单的方式?

2、客户端签名

所以我当然选择服务端签名了,前面的通通跳过,要是有后端的别问我,我就一大白,其他的不懂,咱们直接到这一步
在这里插入图片描述
首先就是一个大坑
import crypto from ‘crypto-js’;
import { Base64 } from ‘js-base64’;
我就问你这两个文件哪儿来的??????????????!!!!!!
问题不大,直接上链接 npm搜索库https://www.npmjs.com/,还好之前有存货
然后复制 crypto-jsjs-base64
完美 ,crypto-js 搜索第一个就是,然后搜索js-base64,
问题在这儿 js-base64,这个文件我下载的第一个,名字一摸一样的哪个
但是出错了,源代码:

import crypto from 'crypto-js';
import { Base64 } from 'js-base64';

// 计算签名。
function computeSignature(accessKeySecret, canonicalString) {
  return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
}

const date = new Date();
date.setHours(date.getHours() + 1);
const policyText = {
  expiration: date.toISOString(), // 设置policy过期时间。
  conditions: [
    // 限制上传大小。
    ["content-length-range", 0, 1024 * 1024 * 1024],
  ],
};

async function getFormDataParams() {
  const credentials = await axios.get('/getToken')
  const policy = Base64.encode(JSON.stringify(policyText)) // policy必须为base64的string。
  const signature = computeSignature(credentials.AccessKeySecret, policy)
  const formData = {
    OSSAccessKeyId: credentials.AccessKeyId,
    signature,
    policy,
    'x-oss-security-token': credentials.SecurityToken 
  }
  return formData
}

这里

const policy = Base64.encode(JSON.stringify(policyText)) // policy必须为base64的string

报错告诉我 encode is not a function

经过排查,其实是Base64 这个引用根本就找不到,打印 { Base64 },就这里面的东西,找不到。所以后面的 encode就更找不到了
所以我换这个了base-64 ,我用的第一个,原来的包删掉了,然后啥都不换,就可以使用了,这个问题找好久。

3、封装oss请求STS签名的网络请求方法

需要更改的为上面js,代码的这个部分

const credentials = await axios.get('/getToken')

这个网络请求,写自己后台提供的啊。
以防万一,我给你们贴一下我自己写的

// 上传oss获取临时token
		async getOSSToken({commit,state}) {
			// 计算签名。
			function computeSignature(accessKeySecret, canonicalString) {
			  return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
			}
			
			const date = new Date();
			date.setHours(date.getHours() + 1);
			const policyText = {
			  expiration: date.toISOString(), // 设置policy过期时间。
			  conditions: [
			    // 限制上传大小。
			    ["content-length-range", 0, 1024 * 1024 * 1024],
			  ],
			};
			
			//获取临时信息
			let data = {
				token:store.state.token,
			}
			let res = await http({url:"account/get_oss_token",data:data})
			console.log("获取后台OSStoken",res.data.dataMap);
			const policy = base64.encode(JSON.stringify(policyText)) // policy必须为base64的string。
			const signature = computeSignature(res.data.dataMap.AccessKeySecret, policy)
			const formData = {
				OSSAccessKeyId: res.data.dataMap.AccessKeyId,
				signature,
				policy,
				SecurityToken: res.data.dataMap.SecurityToken,
				OssFileName:res.data.dataMap.OssFileName
			}
			return formData
		},

至于各个命名是什么意思,文档里面有小程序阿里云oss前端直传_第1张图片

三、使用方法

外部,引入,mapActions,然后在methods引入方法,然后直接调用的代码在下面。

async upLoadOSS(newAccount){
	let that = this
	let timestamp = new Date().getTime()
	console.log('开始上传语音');
	let res = await that.getOSSToken()
	const host = "https://*****.oss-cn-######.aliyuncs.com"
	const signature = res.signature;
	const ossAccessKeyId = res.OSSAccessKeyId
	const policy = res.policy
	const SecurityToken = res.SecurityToken
	const OSSpath = "voice/" + Math.floor(that.uid/10000) + "/" + that.uid + "/" + timestamp + '.mp3'
	//上面这一步是更具用户的uid是数字几打头的,然后创建的文件夹,方便之后好找,
	//这个上传,如果目的地没有你写的文件夹,oss会在上传的时候,立马给你现造一个文件夹,方便的很~
	const key = res.OssFileName +"/" + OSSpath
	//res.OssFileName,这个是服务器返回的,是测试服,还是正式服的路径地址
	console.log("___________________________________++++",key)
	uni.uploadFile({
		url: host, // 开发者服务器的URL。
		filePath: that.mine.voiceUrl,
		name: 'file', // 必须填file。
		formData: {
			key,
			policy,
			OSSAccessKeyId: ossAccessKeyId,
			signature,
			'x-oss-security-token': SecurityToken // 使用STS签名时必传。
		},
		success: (res) => {
			if (res.statusCode === 204) {
				console.log('上传成功');
			}else{
				console.log('请求成功,但是上传失败');
			}
		},
		fail: err => {
			console.log('请求上传失败');
		}
	});
},

4、上传回调

uni.uploadFile,用一个参数接收,会有个进度回调。不过这个就不是oss的文档了,是uniapp的问文档。

var uploadTask = uni.uploadFile({
    url: 'https://www.example.com/upload', //仅为示例,并非真实接口地址。
    complete: ()=> {}
});
uploadTask.abort();

来,各位大哥们,链接直达~ uni.uploadFile(OBJECT)

帮到你的话,点个赞吧d=====( ̄▽ ̄*)b

——Lazy33

你可能感兴趣的:(小程序,vue.js,react.js,html5)