Thinkphp6+Uniapp+微信小程序上传图片到阿里云OSS

本文详细介绍了如何在微信小程序中使用阿里云OSS进行文件上传,包括开通OSS服务、创建Bucket、使用STS临时凭证、配置RAM用户权限、生成签名以及处理跨域和微信小程序的接入。
摘要由CSDN通过智能技术生成

阿里云OSS

阿里云对象存储 OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务。本实例微信小程序直传文件参考官方文档:https://help.aliyun.com/zh/oss/use-cases/use-wechat-mini-programs-to-upload-objects,使用STS临时访问凭证访问OSS官方文档:https://www.alibabacloud.com/help/zh/oss/developer-reference/use-temporary-access-credentials-provided-by-sts-to-access-oss#concept-xzh-nzk-2gb,另外使用STS进行临时授权之PHP授权访问参考官方文档:https://help.aliyun.com/zh/oss/developer-reference/authorize-access-2?spm=a2c4g.11186623.0.0.11af3505HVTTOL

使用STS授权用户直接访问OSS的流程如下:

图片

开通阿里云OSS

开通阿里云oss试用版:https://free.aliyun.com/?pipCode=oss&spm=5176.7933691.J_5253785160.4.1bbb2c47VFQdPM

图片

创建存储空间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成功

  • 46
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值