小程序(uniapp)上传头像至OSS(阿里云)--保姆级

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 前言自微信小程序改版以来,现在获取用户的头像和昵称就不能直接通过wx.getUserInfo获取了。而是需要用户主动在登录后填写自己的昵称和头像,微信只是提供一个一键填写的快捷操作让用户直接使用自己已有的微信昵称或头像。

小程序(uniapp)上传头像至OSS(阿里云)--保姆级

前言


微信小程序改版以来,现在获取用户的头像和昵称就不能直接通过wx.getUserInfo获取了。而是需要用户主动在登录后填写自己的昵称和头像,微信只是提供一个一键填写的快捷操作让用户直接使用自己已有的微信昵称或头像。

如果是想做一个比较完善的小程序系统,那么头像昵称的修改可谓是每个带用户的小程序开发都需要经历的。

昵称还好,就是一个文本字符串,但是头像的话我们就需要上传至自己的服务器或者是一些云对象存储服务,这里我选择的是阿里云OSS服务,下面开始我的保姆级教程

流程概览


如上是整个上传头像的一个时序图,总的来说有这五步:

  1. 通过微信自带组件获取用户选择头像的临时文件路径
  2. 获取对OSS的操作授权
  3. 配置后端服务生成临时授权的服务
  4. 获取授权并上传文件至OSS
  5. 将新的头像路径保存到数据库用户表中

好,接下来我们就以上述五步慢慢道来:

1. 获取头像临时路径



据描述:是要将 button 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径。

所以笔者编写了如下代码:

// template
<button class="avatar-wrapper" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
  <uni-icons type="forward" size="30" color="#D3D3D3"></uni-icons>
</button>


// script
function onChooseAvatar(e: any) {
  console.log("choose avatar: ", e.detail);
  user.avatarUrl = e.detail.avatarUrl;
}


为了让button样式透明,所以style代码如下

.avatar-wrapper {
  padding-left: 0;
  padding-right: 0;
  height: 50px;
  line-height: 50px;
  background-color: transparent;
  border-color: transparent;
}
.avatar-wrapper::after {
  border: none;
}


这里笔者在button里面包裹了一个icon,因为我不想要button的样式,而仅仅用户点击icon就可以修改头像。

此时我们点击就可以获取头像的临时路径了:

然后我们选择微信头像或者本地上传的图片后就可以出现如下的日志信息:

到这里,我们这一步就已经完成了,已经获取到如上的头像临时路径了...

2. 获取OSS操作授权


这里假设你已经开通了OSS服务 ,开通过程非常简单,毕竟花钱的过程一般来说都是非常简单的,一步到位🤬。这里就不过多赘述了。

如果你想要你的OSS服务拥有自己的专属域名以及CDN加速的话,可以查看我之间写的这篇文章--CDN实践配置+原理篇

首先我们创建一个我们阿里云账号的子用户,这个子用户我们后续会将它授权给我们的服务器,让我们的服务器操作该子用户,拥有其拥有的权限。你的就是我的🤭

1)配置阿里云-访问控制

按照上述的流程点击创建后,就会出现如下页面,这里值得注意的是我们需要保存好其中的accessKeyId以及accessKeySecret

拥有这个Id+Secret相当于我们就拥有了这个用户的身份,就可以操作该身份具有的资源了,但是此时我们还没有赋予其任何权限,所以这里我们赋予其操作OSS的权限,尽量不要赋予过多的权限,做好权限收敛:

当然,如果你有多个用户有同样的权限操作,也可以使用用户组进行管理,这里不展开了。

点击添加权限,选择AliyunOSSFullAccess

2)配置阿里云-OSS-细化授权

然后我们继续对OSS进行细化配置:

3)配置阿里云-OSS-跨域访问

如果你的OSS之前已经可以访问了,这里就不需要配置了,如果是第一次配置,那么记得还要对OSS进行跨域访问的配置,这也是很多网友出现403的主要原因。

好,此时我们就拥有了一个有效的AccesssKeyIdAccessKeySecretl了

3. 配置服务器


这里我使用的是服务端签名,你也可以使用客户端签名临时凭证。并且我这里使用的后端技术栈是NestJS + GraphQl,如果你是其他技术栈,可以参考原官方文档进行自定义

0)安装

npm i crypto-js @types/crypto-js


/src/utils/oss.interface.ts

export interface MpUploadOssHelperOptions {
  // 阿里云账号AccessKey
  accessKeyId: string;
  // 阿里云账号AccessId
  accessKeySecret: string;
  // 限制参数的生效实践,单位为小时,默认值为1
  timeout?: number;
  // 限制上传文件大小,单位为MB,默认值为10
  maxSize?: number;
}


2)/src/utils/oss.ts

import * as crypto from 'crypto-js';
import { MpUploadOssHelperOptions } from './oss.interface';
// 详见:https://help.aliyun.com/document_detail/92883.html
export class MpUploadOssHelper {
  private accessKeyId: string;
  private accessKeySecret: string;
  private timeout: number;
  private maxSize: number;
  constructor(options: MpUploadOssHelperOptions) {
    this.accessKeyId = options.accessKeyId;
    this.accessKeySecret = options.accessKeySecret;
    // 限制参数的生效时间,单位为小时,默认值为1。
    this.timeout = options.timeout || 1;
    // 限制上传文件的大小,单位为MB,默认值为10。
    this.maxSize = options.maxSize || 10;
  }
  createUploadParams() {
    const policy = this.getPolicyBase64();
    const signature = this.signature(policy);
    return {
      OSSAccessKeyId: this.accessKeyId,
      policy: policy,
      signature: signature,
    };
  }
  getPolicyBase64() {
    const date = new Date();
    // 设置policy过期时间。
    date.setHours(date.getHours() + this.timeout);
    const srcT = date.toISOString();
    const policyText = {
      expiration: srcT,
      conditions: [
        // 限制上传文件大小。
        ['content-length-range', 0, this.maxSize * 1024 * 1024],
      ],
    };
    const buffer = Buffer.from(JSON.stringify(policyText));
    return buffer.toString('base64');
  }
  signature(policy) {
    return crypto.enc.Base64.stringify(
      crypto.HmacSHA1(policy, this.accessKeySecret)
    );
  }
}


3)src/oss/models/oss.model.ts

import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class Oss {
  @Field()
  OSSAccessKeyId: string;
  @Field()
  policy: string;
  @Field()
  signature: string;
}


4)src/oss/oss.module.ts

import { Module } from '@nestjs/common';
import { OssService } from './oss.service';
import { OssResolver } from './oss.resolver';
@Module({
  providers: [OssService, OssResolver],
})
export class OssModule {}


5)src/oss/oss.service.ts

import { Injectable } from '@nestjs/common';
import { MpUploadOssHelper } from 'src/utils/oss';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class OssService {
  constructor(private readonly configService: ConfigService) {}
  getPostObjectParams() {
    const mpHelper = new MpUploadOssHelper({
      accessKeyId: this.configService.get<string>('ACCESS_KEY_ID'),
      accessKeySecret: this.configService.get<string>('ACCESS_KEY_SECRET'),
      timeout: 1,
      maxSize: 1,
    });
    // 生成参数
    const params = mpHelper.createUploadParams();
    return params;
  }
}


注意:这里我是通过环境变量获取的IDKEY,环境变量的使用可参考这篇文章

6)src/oss/oss.resolve.ts或者src/oss/oss.controller.ts

这里就体现了service作为业务层的作用了,无论我们是想使用GraphQL,还是使用REST API暴露接口,都可以非常灵活的替换,如下是GraphQL的代码:


import { UseGuards } from '@nestjs/common';
import { Resolver, Query } from '@nestjs/graphql';
import { GqlAuthGuard } from 'src/auth/gql-auth.guard';
import { Oss } from './models/oss.model';
import { OssService } from './oss.service';
@Resolver()
export class OssResolver {
  constructor(private readonly ossService: OssService) {}
  @UseGuards(GqlAuthGuard)
  @Query(() => Oss)
  getPostObjectParams() {
    return this.ossService.getPostObjectParams();
  }
}


演示:

4. 上传文件至OSS


如下代码,这里使用的是GraphQL请求的接口,如果你是使用的REST API,基本流程也是一样的:

async function uploadAvatar(filePath: string) {
  // 1. 请求服务端签名凭证
  const { execute } = useQuery({ query: getPostObjectParamsGQL });
  uni.showLoading({ title: "正在请求上传凭证中..." });
  const { error, data } = await execute();
  if (error) {
    uni.showToast({
      title: `上传头像失败: ${error}`,
      icon: "error",
      duration: 2000,
    });
    throw new Error(`上传头像失败: ${error}`);
  }
  // 2. 上传图片至oss
  const { OSSAccessKeyId, policy, signature } = data?.getPostObjectParams || {};
  const imgType = filePath.split(".").pop();
  const key = `wxmp/${userData?.id}.${imgType}`;
  uni.showLoading({ title: "正在上传图片中..." });
  const ossRes = await uniUploadFile({
    url: ossHost, // 开发者服务器的URL。
    filePath,
    name: "file", // 必须填file。
    formData: {
      key,
      policy,
      OSSAccessKeyId,
      signature,
    },
  });
  uni.hideLoading();
  return ossHost + "/" + key;
}


上述代码我是以用户的uid重命名图片文件的,就是key这个属性值,你也可以自定义你自己的文件命名方式。

演示:

然后OSS中就可以查看到这张图片了:

5. 保存数据库用户表


这一步其实就很简单了,也没什么参考价值,就是请求API,然后保存到数据库就可以了,具体代码就不贴了,如下是效果:

最后


小程序的开发几乎是程序员的必备操作,自带流量,前期非常好用,不过就是开发文档确实看着不舒服,平台改版我们也需要跟着改版...

然后用户登录以及自定义头像都是小程序们非常常见的操作,这里演示一下过程希望对你有所帮助,如果有操作不当,欢迎在评论区中友善指出..


相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
4月前
|
机器学习/深度学习 人工智能 专有云
人工智能平台PAI使用问题之怎么将DLC的数据写入到另一个阿里云主账号的OSS中
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
19天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
3月前
|
存储 机器学习/深度学习 弹性计算
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
|
4月前
|
小程序
尝试使用阿里云服务器搭建微信小程序
华北电力大学核工程大一学生,出于对编程的热爱与大创项目需求,涉足微信小程序搭建。初期在实验指导下克服不熟悉编程的困难,但后期发现教程引导不足,尤其是对于代码定位缺乏清晰指引。建议加强网页图像指导,以适应不同编程水平用户,尤其是新手。
尝试使用阿里云服务器搭建微信小程序
|
4月前
|
消息中间件 分布式计算 DataWorks
DataWorks产品使用合集之如何使用Python和阿里云SDK读取OSS中的文件
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
4月前
|
存储 运维 安全
阿里云OSS的优势
【7月更文挑战第19天】阿里云OSS的优势
194 2
|
4月前
|
存储 API 开发工具
阿里云OSS
【7月更文挑战第19天】阿里云OSS
188 1
|
4月前
|
存储 弹性计算 对象存储
预留空间是什么?阿里云OSS对象存储预留空间说明
阿里云OSS预留空间是预付费存储产品,提供折扣价以锁定特定容量,适用于抵扣有地域属性的Bucket标准存储费用及ECS快照费。通过购买预留空间,如500GB通用预留+100GB标准-本地冗余存储包,用户可优化成本。
210 4
|
4月前
|
人工智能 对象存储
【阿里云AI助理】自家产品提供错误答案。阿里云OSS 资源包类型: 下行流量 地域: 中国内地通用 下行流量包规格: 300 GB 套餐: 下行流量包(中国内地) ,包1年。那么这个是每月300GB,1年是3600GB的流量;还是1年只有300GB的流量?
自家产品提供错误答案。阿里云OSS 资源包类型: 下行流量 地域: 中国内地通用 下行流量包规格: 300 GB 套餐: 下行流量包(中国内地) ,包1年。那么这个是每月300GB,1年是3600GB的流量;还是1年只有300GB的流量?
128 1
|
4月前
|
存储 小程序 API
【微信小程序-原生开发+云开发+TDesign】修改用户头像(含wx.chooseMedia,wx.cloud.uploadFile,wx.cloud.deleteFile的使用)
【微信小程序-原生开发+云开发+TDesign】修改用户头像(含wx.chooseMedia,wx.cloud.uploadFile,wx.cloud.deleteFile的使用)
82 0
【微信小程序-原生开发+云开发+TDesign】修改用户头像(含wx.chooseMedia,wx.cloud.uploadFile,wx.cloud.deleteFile的使用)