头图

阿里云对象存储 OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务。本实例微信小程序直传文件参考官方文档:https://help.aliyun.com/zh/oss/use-cases/use-wechat-mini-prog...,使用STS临时访问凭证访问OSS官方文档:https://www.alibabacloud.com/help/zh/oss/developer-reference/...,另外使用STS进行临时授权之PHP授权访问参考官方文档:https://help.aliyun.com/zh/oss/developer-reference/authorize-...。使用STS授权用户直接访问OSS的流程如下:
图片
开通阿里云OSS开通阿里云oss试用版:https://free.aliyun.com/?pipCode=oss&spm=5176.7933691.J_52537...
图片
创建存储空间Bucket存储空间(Bucket)是用于存储对象(Object)的容器
图片
创建Bucket存储目录文件列表新建test目录作为图片存放位置
图片
获取Bucket名称和Bucket域名点击浏览进入Bucket基本信息,保存存储空间名称、Endpoint地域节点、Bucket域名
图片
创建RAM用户与角色云账号 AccessKey 是您访问阿里云 API 的密钥,具有账户的完全权限,使用 RAM 用户(而不是云账号)的 AccessKey 进行 API 调用
图片
获取AccessKey ID和AccessKey Secret
图片
为RAM用户添加权限:AliyunOSSFullAccess、AliyunSTSAssumeRoleAccess,在左侧搜索框输入AliyunOSSFullAccess与AliyunSTSAssumeRoleAccess进行添加,然后点确定进行保存。
图片
创建角色:第一步选择阿里云账号
图片
第二步配置角色
图片
创建完成之后点击“为角色授权”
图片
还是添加AliyunOSSFullAccess、AliyunSTSAssumeRoleAccess权限,在左侧搜索框输入AliyunOSSFullAccess与AliyunSTSAssumeRoleAccess进行添加,然后点确定进行保存。
图片
获取角色ARN
图片
为角色授予上传文件的权限在创建权限策略页面,单击脚本编辑,然后在策略文档输入框中赋予角色向目标存储空间examplebucket下的目录上传文件的权限。具体配置示例如下。
图片

图片
创建Bucket授权策略
图片
配置Bucket跨域访问客户端进行表单直传到OSS时,会从浏览器向OSS发送带有Origin头的请求消息。OSS对带有Origin头的请求消息会进行跨域规则(CORS)的验证。因此需要为Bucket设置跨域规则以支持Post方法。
图片
微信小程序配置域名白名单为微信小程序配置域名白名单,以实现微信小程序和OSS Bucket之间的正常通信。登录微信小程序平台,将上传和下载的合法域名填写为Bucket的外网访问域名。
图片
服务端生成签名使用服务端签名时,需要先搭建一个签名服务,然后由客户端调用签名服务生成签名。本例使用Thinkphp6生成签名。首先安装thinkphp6:


C:\phpstudy_pro\WWW> composer create-project topthink/think tp

使用composer require alibabacloud/sts-20150401命令安装STS依赖,使用composer require alibabacloud/sdk命令安装PHP SDK依赖。


C:\phpstudy_pro\WWW>tp> composer require alibabacloud/sts-20150401
C:\phpstudy_pro\WWW>tp> composer require alibabacloud/sdk

创建生成签名控制器api.php、配置文件upload.php
图片
upload.php文件配置阿里云oss参数


<?php
return [
'storage' => '0',
'oss_ak' => '',//阿里云AccessKeyId   
'oss_sk' => '',//阿里云AccessKeySecret'
'oss_host' => '',//阿里云Bucket 域名
'oss_endpoint' => 'oss-cn-hangzhou.aliyuncs.com',//阿里云 Endpoint(地域节点)
'oss_bucket' => '',//bucket名称
'oss_role_arn' => '',  // 角色访问控制RoleArn
'oss_role_session_name' => 'stahangdeng', // 临时凭证名称,随意
];

后端代码实现

<?php

namespace app\controller;

use think\Request;
use think\facade\Config;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;

use app\BaseController;

class Api extends BaseController
{
    private $ak='';
    private $sk='';
    private $host='';
    private $bucket='';
    private $endpoint='';
    private $roleArn='';
    private $roleSessionName='';
    
    public function __construct(Request $request)
{
        //配置阿里云参数
        empty($this->ak) && $this->ak = Config::get('upload.oss_ak');
        empty($this->sk) &&  $this->sk = Config::get('upload.oss_sk');
        empty($this->host) &&  $this->host = Config::get('upload.oss_host');
        empty($this->bucket) &&  $this->bucket = Config::get('upload.oss_bucket');
        empty($this->endpoint) &&  $this->endpoint = Config::get('upload.oss_endpoint');
        empty($this->roleArn) &&  $this->roleArn = Config::get('upload.oss_role_arn');
        empty($this->roleSessionName) &&  $this->roleSessionName = Config::get('upload.oss_role_session_name');
    }

    /**
     * 阿里云Sts凭证
     */
    public function getStsToken()
{
        AlibabaCloud::accessKeyClient($this->ak, $this->sk)
            ->regionId('cn-hangzhou')
            ->asDefaultClient();

        try {
            $result = AlibabaCloud::rpc()
                ->product('Sts')
                ->scheme('https') // https | http
                ->version('2015-04-01')
                ->action('AssumeRole')
                ->method('POST')
                ->host('sts.aliyuncs.com')
                ->options([
                    'query' => [
                        'RegionId' => "cn-hangzhou",
                        'RoleArn' => $this->roleArn,
                        'RoleSessionName' => $this->roleSessionName,
                    ],
                ])
                ->request();
                
            $resultObj = $result->toArray();
            $credentials = $resultObj['Credentials'];
            $credentials['host'] = $this->host;
            return json($credentials);
        } catch (ClientException $e) {
            return error($e->getErrorMessage());
        } catch (ServerException $e) {
            return error($e->getErrorMessage());
        }
    }

uniapp搭建小程序创建项目
图片
把项目运行到微信开发者工具
图片
运行到小程序模拟器
图片

图片
安装crypto-js和base64-js执行以下命令安装js


C:\phpstudy_pro\WWW\wx-uniapp> npm install crypto-js
C:\phpstudy_pro\WWW\wx-uniapp> npm install js-base64

引入js


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

前端代码实现

在wx-uniapp\pages\index\index.vue文件添加以下代码

<template>
<view class="content">
<view class="cell-left">
<view class="cell-text">照片上传:</view>
<view class="cell-text" style="color: #8C8C8C;width: 180px;">(最多上传3张图片)</view>
</view>
<view class="cell-left">
<view class="qtpicker">
<!-- 选中待上传的图片 -->
<view class="preImgs" v-for="(val,index) in preImgUrl" :key='index'>
<image style="border-radius: 6px;" mode="" :src="val" @click="showImg(val,index)">
</image>
<!-- 删除某张图片 -->
<view v-show="isShowDelImgBtn">
<image class="cuo" mode="" src="/static/delete-icon.png" @click="delImg(index)">
</image>
</view>
</view>

<view v-show="isShowAddImgBtn">
<view class="img-item upload-icon" @click="chooseImg"></view>
</view>
</view>
</view>
</view>
</template>

<script>
import crypto from 'crypto-js';
import { Base64 } from 'js-base64';
export default {
data() {
return {
//title: 'Hello',
preImgUrl: [], //本地预览的图片数据
ossAccessKeyId:'',
ossAccessKeySecret:'',
host:'',
securityToken:'',
policy:'',
isShowDelImgBtn:true,
isShowAddImgBtn: true,
}
},
onLoad() {

},
created() {
this.getStsToken();
},
methods: {
// 将方法标记为异步
async getStsToken() {
let that = this
// 调用后端接口
const result = uni.request({
url: 'http://localhost/api/getStsToken',
method: 'POST',
}).then(response => {
// response 就是 Promise 的 [[PromiseResult]] 属性对应的值
const { data } = response;
console.log(data);
// 现在你可以直接访问和过滤data中的内容
this.host = data.host;
that.ossAccessKeyId = data.AccessKeyId;
that.ossAccessKeySecret = data.AccessKeySecret;
that.securityToken = data.SecurityToken;
const policyText = {
expiration: data.Expiration, // policy过期时间。根据自己接口返回的格式进行获取数据
conditions: [
// 限制上传大小。
["content-length-range", 0, 1024 * 1024 * 1024],
],
};
this.policy = Base64.encode(JSON.stringify(policyText)) // policy必须为base64的string。
}).catch(error => {
console.error('获取STS Token时出错:', error);
});
},

computeSignature(accessKeySecret, canonicalString) {
return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
},

// 选择图片
chooseImg() {
let that = this

uni.chooseImage({
// count:  允许上传的照片数量
count: 3, //h5无法限制
// sizeType:  original 原图,compressed 压缩图,默认二者都有
sizeType: "original,compressed",
success: function(res) { //选择成功,将图片存入本地临时路径,可删除,可查看,等待上传
console.log(res, '选择成功')

// 如果限制图片大小,则添加判断
res.tempFiles.map(val => {
// 判断本次上传限制的图片大小
if (val.size > 10485760) {
uni.showToast({
icon: 'none',
title: '上传的图片大小不超过10M'
})
return
}

// 判断本次最多上传多少照片
that.imgNum++
if(that.imgNum==3){
that.isShowAddImgBtn=false
uni.showToast({
icon: 'none',
title: '最多上传3张图片'
})
}
if (that.imgNum > 3) {
that.imgNum = 3
uni.showToast({
icon: 'none',
title: '上传的图片最多不能超过3张'
})
return
}
const filePath = val.path; // 待上传文件的文件路径。
//把临时路径添加进数组,渲染到页面
that.preImgUrl.push(filePath) 

// 加入时间戳-以免文件名重复
let unixTime = String(Date.parse(new Date()) / 1000)

//获取最后一个.的位置
let fileIndex = filePath.lastIndexOf(".");
//获取文件后缀
let fileExt = filePath.substring(fileIndex + 1);
//文件名
    let key = 'test/'+unixTime+'.'+fileExt;

const signature = that.computeSignature(that.ossAccessKeySecret, that.policy);
console.log(signature);
//上传图片到阿里云oss
const host = that.host;
const policy = that.policy;
const ossAccessKeyId = that.ossAccessKeyId;
const securityToken = that.securityToken; 

uni.uploadFile({
url: host,
filePath: filePath,
name: 'file', // 必须填file。

formData: {
key,
policy,
OSSAccessKeyId: ossAccessKeyId,
signature,
'x-oss-security-token': securityToken,
//success_action_status: 200, // 自定义成功返回的http状态码,默认为204
},
success: (res) => {
console.log(res);
if (res.statusCode === 204) {
//console.log('上传成功');
}
},
fail: err => {
console.log(err);
}
});
})
}
})
},
//点击小图查看大图片
showImg(val, index) {
console.log(val, '点击了')
let that = this
uni.previewImage({
// 对选中的图片进行预览
urls: that.preImgUrl, //图片数组  // urls:['','']  图片的地址 是数组形式
current: index, //当前图片的下标
})
},

//删除某张图片,从本地的临时路径图片中, 删除路径即可
delImg(index) {
this.imgNum--;
this.preImgUrl.splice(index, 1)
if(this.imgNum<3){
this.isShowAddImgBtn=true;
}
},
}
}
</script>

<style lang="scss" scoped>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}

.text-area {
display: flex;
justify-content: center;
}

.title {
font-size: 36rpx;
color: #8f8f94;
}

.upload-icon {
box-sizing: border-box;
border: 2rpx solid #bfbfbf;
}

.upload-icon:before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 60rpx;
height: 6rpx;
background-color: #bfbfbf;
margin: -3rpx 0 0 -30rpx;
border-radius: 5rpx;
}

.upload-icon::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 6rpx;
height: 60rpx;
background-color: #bfbfbf;
margin: -30rpx 0 0 -3rpx;
border-radius: 5rpx;
}

.cell-left {
display: flex;
align-items: center;
padding: 8px;
.cell-icon {
width: 50rpx;
height: 50rpx;
}

.cell-text {
color: #595959 ;
font-size: 15px;
margin-left: 20rpx;
//width: 180rpx;
}
}

.img-item {
width: 150rpx;
height: 150rpx;
position: relative;
box-sizing: border-box;
margin: 15rpx;

.img {
width: 100%;
height: 100%;
}

.img-delete-box {
width: 40rpx;
height: 40rpx;
position: absolute;
right: 0;
top: 0;

.img-delete-icon {
width: 100%;
height: 100%;
}
}

}

.qtpicker {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 auto;
padding: 10rpx 0;

.preImgs {
margin: 13rpx;
position: relative;

image {
width: 200rpx;
height: 200rpx;
}

.cuo {
width: 17pt;
height: 17pt;
//line-height: 12px;
//text-align: center;
///* font-size: 16px; */
//border-radius: 50%;
//background-color: #223E4B;
//color: #FFFFFF;
position: absolute;
right: 0px;
top: 0px;
}
}
}
</style>

上传图片前端微信小程序开发工具点击图片上传,图片上传成功返回code204
图片
Bucket文件列表显示上传图片成功
图片
点击图片详情,图片正常显示
图片
到此微信小程序上传图片到阿里云oss成功


ICEMAN
0 声望0 粉丝