前言
按照我以前的风格,现在这篇文章也是,在网上找到各个版本的代码,发现无法使用。小程序作为当前最热门的模块,开发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搜索库/,还好之前有存货
然后复制crypto-js,js-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获取临时tokenasync 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},
至于各个命名是什么意思,文档里面有
三、使用方法
外部,引入,mapActions,然后在methods引入方法,然后直接调用的代码在下面。
async upLoadOSS(newAccount){let that = thislet timestamp = new Date().getTime()console.log('开始上传语音');let res = await that.getOSSToken()const host = "https://*****.oss-cn-######."const signature = res.signature;const ossAccessKeyId = res.OSSAccessKeyIdconst policy = res.policyconst SecurityToken = res.SecurityTokenconst 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: '/upload', //仅为示例,并非真实接口地址。complete: ()=> {}});uploadTask.abort();
来,各位大哥们,链接直达~ uni.uploadFile(OBJECT)
帮到你的话,点个赞吧d=====( ̄▽ ̄*)b
——Lazy33