我的 Serverless 实战—SCF构建小型服务端并结合uni-app

2024-01-16 20:50

本文主要是介绍我的 Serverless 实战—SCF构建小型服务端并结合uni-app,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【本文正在参与“100%有奖|我的Serverless 实战”征稿活动】,活动地址:https://marketing.csdn.net/p/15940c87f66c68188cfe5228cf4a0c3f

使用腾讯云SCF构建小型服务端并结合uni-app()小程序

我们这里手写了一个nodejs环境下的用户体系
使用了之前写的一个数据库连接插件dmhq-mysql-pool比较垃圾 凑合用
文档地址为 https://github.com/dmhsq/dmhsq-mysql-pool/blob/main/README.md
也使用了md5 npm install js-md5

这里使用邮箱发送验证码
先在本地写好 再上传云函数

配置数据库连接

安装 npm install dmhsq-mysql-pool

新建一个文件db.js

const database = require("dmhsq-mysql-pool");
const configs = {host: 'xxxx',port: 'xxxx',user: 'xxxx',password: 'xxxx',database: "xxxx"
}
let user = new database(configs).table("user")
let codes = new database(configs).table("email")
module.exports = {user,codes
};

用户数据表名 user
在这里插入图片描述

验证码表 名email 由于只用到邮箱验证码
在这里插入图片描述

配置邮箱发送模块

这里的user 和 pass 为STMP获取 在各大邮箱的设置可以找到
邮箱转发服务 npm install nodemailer
nodemailer文档

const nodemailer = require('nodemailer')const transporter = nodemailer.createTransport({service: 'qq', // no need to set host or port etc.auth: {user: 'xxxxx@qq.com',pass: 'xxxxxxx'}
});const sendCode = async (email,code,time) => {let message = {from: "验证码<xxxxx@qq.com>",to: email,subject: "验证码服务",html: `<html><head><meta charset="utf-8"><title></title></head><body><div><p style="font-size: 20px;">欢迎您使用,您的验证码为 <span style="color: blue;font-size: 30px;font-weight: 800;">${code}</span> ,有效时间为${time/60}分钟, 请勿泄露并及时验证</p><div style="margin-top: 50px;"></div><p style="color: red;font-size: 25px;">请勿回复</p></div></body></html>`};await transporter.sendMail(message)return {code:0,msg:"邮件已发送,如果没有收到,请检查邮箱"}
}module.exports = {sendCode};

编写简单用户体系

const {user,codes
} = require("./db.js");
const {sendCode
} = require("./email.js");
const md5 = require("js-md5")//注册模块
const sign = async (username, password) => {const dfp = passwordpassword = md5(password);let isH = await user.where({username}).get();if(isH.data.length>0){return {code: 5742,msg: "用户名已被占用",}}const _id = md5(Math.random().toString(36)).substr(0, 10);let res = await user.add({username,password,_id}).get();let rsp = {code: 5741,msg: "注册失败",}if (res.code == 0) {let userRes = await login(username, dfp);rsp = {code: 0,msg: "注册成功"}if (userRes.code == 0) {rsp.data = userRes.userInfo}}return rsp;
}//登陆模块
const login = async (username, password) => {password = md5(password)let res = await user.where({username,password}).get()if (!res.data.length) {return {code: 9001,msg: "用户名或者密码错误"}} else {let token = md5(md5(Math.random().toString(36)) + md5(Math.random().toString(36)));const tokenExpired = parseInt(Date.parse(new Date()).toString().substr(0, 10)) + 72000;const last_login_time = parseInt(Date.parse(new Date()).toString().substr(0, 10));let qres = await user.updata({token_expired: tokenExpired,token,last_login_time}).where({username}).get();if (qres.code == 0) {return {code: 0,userInfo: {token,tokenExpired,username}}} else {return {code: 9002,msg: "登陆失败",data: qres}}}
}//邮箱发送模块
const sendEmailCode = async (email, type) => {const randomStr = '00000' + Math.floor(Math.random() * 1000000)const code = randomStr.substring(randomStr.length - 6);let time = 3600const check_time = parseInt(Date.parse(new Date()).toString().substr(0, 10)) + time;let res = {}res = await sendCode(email, code, time)if (res.code == 0) {await codes.add({email,code,check_time,state: 0,type}).get();} else {res = {code: 4046,msg: "发送失败"}}return res
}//验证码校验
const checkCode = async (email, code, type) => {let result = await codes.where({email,code,type}).sort({check_time: "DESC"}).get();let data = result.data;let res = {}if (data.length == 0) {res = {code: 4048,msg: "验证码错误"}} else {data = data[0]const check_times = parseInt(Date.parse(new Date()).toString().substr(0, 10));if (data.state == 0 & data.check_time > check_times) {await codes.updata({state: 1}).where({email}).get()res = {code: 0,msg: "验证通过"}} else if (data.check_time < check_times) {res = {code: 4044,msg: "验证码失效"}} else if (data.state == 1) {res = {code: 4045,msg: "验证码已经验证"}} else {res = {code: 4048,msg: "验证码错误"}}}return res;
}//邮箱绑定
const bind = async (username, email, code) => {const check_code = await checkCode(email, code, "bind");const check_user = await user.where({username,email}).get();let res = {}if (check_user.data.length > 0) {res = {code: 74174,msg: "用户已经绑定邮箱"}} else {if (check_code.code == 0) {const datas = await user.updata({email}).where({username}).get();if (datas.code == 0) {res = {code: 0,msg: "绑定成功"}}}else{res = check_code}}return res;
}//邮箱解除绑定
const unbind = async (username, email, code) => {const check_code = await checkCode(email, code, "unbind");const check_user = await user.where({username,email}).get();let res = {}if (check_user.data.length == 0) {res = {code: 74175,msg: "用户还未绑定邮箱"}} else {if (check_code.code == 0) {const datas = await user.updata({email: ""}).where({username}).get();if (datas.code == 0) {res = {code: 0,msg: "解除绑定成功"}}}else{res = check_code}}return res;
}//邮箱校检登录
const checkCodeLogin = async (email, code) => {const ress = await checkCode(email, code, "login")const isH = await user.where({email}).get();if(isH.data.length==0){return {code:9003,msg:"非法邮箱(邮箱未绑定用户)"}}if (ress.code == 0) {let token = md5(md5(Math.random().toString(36)) + md5(Math.random().toString(36)));const tokenExpired = parseInt(Date.parse(new Date()).toString().substr(0, 10)) + 72000;const last_login_time = parseInt(Date.parse(new Date()).toString().substr(0, 10));let qres = await user.updata({token_expired: tokenExpired,token,last_login_time}).where({email}).get();if (qres.code == 0) {res = {code: 0,userInfo: {token,tokenExpired,email}}} else {res = {code: 9002,msg: "登陆失败",data: qres}}}return res;
}//token校检
const checkToken = async (token) => {const reqs = await user.where({token}).get();let res = {}if (reqs.data.length > 0) {const userInfos = reqs.data[0]const check_time = userInfos.token_expired;const now_time = parseInt(Date.parse(new Date()).toString().substr(0, 10));if (check_time > now_time) {res = {code: 0,userInfo: {username: userInfos.username}}} else {res = {code: 7412,msg: "token过期"}}} else {res = {code: 7417,msg: "token非法"}}return res;
}module.exports = {sign,login,sendEmailCode,checkCode,bind,unbind,checkCodeLogin,checkToken
}

编写主程序

const userCenter = require("./user.js")index.main_handler = async (event, context) => {let noCheckAction = ['sign', 'checkToken', 'login', 'checkCode', 'loginByEmail', 'emailCode']let params = event.queryString;let res = {}const {action} = paramsif (noCheckAction.indexOf(action) === -1) {if (!params.token) {res = {code: 401,msg: '缺少token'}return res;}else{let datas = await userCenter.checkToken(params.token)if (datas.code != 0) {res = datasreturn res;}else{params.username = datas.userInfo.username;}}}switch (action) {case "sign": {const {username,password} = params;res = await userCenter.sign(username, password);break;}case "login": {const {username,password} = params;res = await userCenter.login(username, password)break;}case "emailCode": {const {email,type} = params;res = await userCenter.sendEmailCode(email, type)break;}case "checkCode": {const {email,code,type} = params;res = await userCenter.checkCode(email, code, type)break;}case "bind": {const {username,email,code} = params;res = await userCenter.bind(username, email, code)break;}case "unbind": {const {username,email,code} = params;res = await userCenter.unbind(username, email, code)break;}case "loginByEmail": {const {email,code} = params;res = await userCenter.checkCodeLogin(email, code)break;}case "checkToken": {const {token} = params;res = await userCenter.checkToken(token)break;}default: {res = {code: 403,msg: "非法访问"};break;}}return res;
}

创建云函数

在这里插入图片描述

注意这里的执行方法
在这里插入图片描述
选择我们的项目文件夹
在这里插入图片描述
上传文件夹

部署

创建触发器

在这里插入图片描述
在这里插入图片描述

点击api名称管理
在这里插入图片描述

编辑触发器
在这里插入图片描述

关闭集成响应

在这里插入图片描述

测试

触发器 拿到请求地址
在这里插入图片描述
测试注册
在这里插入图片描述

做个小程序

这里使用 uni-app做微信小程序

由于我们只用了 用户模块 那么我们就整合用户模块

页面很简单 登录 注册 邮箱登录 邮箱绑定 邮箱解绑
在这里插入图片描述
在这里插入图片描述
页面代码

<template><view class="content"><view v-if="is_us"><input v-model="username" placeholder="用户名" /><input v-model="password" type="password" placeholder="密码" /><text @click="is_us=false">邮箱验证码登录</text><button @click="login()">登录</button><button @click="register()">注册</button></view><view v-if="!is_us"><input v-model="email" placeholder="邮箱" /><input v-model="code" placeholder="验证码" /><text @click="is_us=true">账号密码登录</text><button @click="sendEmail('login')">发送验证码</button><button @click="loginEm()">登录</button></view><view><view>用户名:{{userInfo.username}}</view><view>token过期时间:{{userInfo.tokenExpired | timeDel }}</view><view>token:{{userInfo.token}}</view></view><view v-if="userInfo.token!=''"><input v-model="email" placeholder="邮箱" /><input v-model="code" placeholder="验证码" /><button @click="sendEmail('bind')">发送绑定验证码</button><button @click="sendEmail('unbind')">发送解绑验证码</button><button @click="bindEm()">绑定</button><button @click="unbindEm()">解绑</button></view><view><view>{{userInfoG}}</view><button @click="getUserInfo()">获取信息</button></view></view>
</template><script>export default {data() {return {title: 'Hello',is_us: true,username:"",password:"",email:"",code:"",userInfo: {username: "未登录",token:"",tokenExpired:""},userInfoG:{}}},filters:{timeDel(val) {if(!val){return ""}var date = new Date(val*1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000var Y = date.getFullYear() + '-';var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();return Y + M + D + h + m + s;}},onLoad() {},methods: {req(action,other){return new Promise(resolve=>{uni.request({method:'POST',url:`xxx/userCenter?action=${action}&${other}`,success:res=>{resolve(res.data)}})})},getUserInfo(){let tokens = uni.getStorageSync('token')this.req('checkToken',`token=${tokens}`).then(res=>{uni.showToast({title:res.msg,icon:'none'})this.userInfoG = JSON.stringify(res)})},register(){this.req('sign',`username=${this.username}&password=${this.password}`).then(res=>{uni.showToast({title:res.msg,icon:'none'})if(res.code==0){let userInfo = res.datauni.setStorageSync("token",userInfo.token)uni.setStorageSync("tokenExpired",userInfo.tokenExpired)this.userInfo = userInfo}})},login(){this.req('login',`username=${this.username}&password=${this.password}`).then(res=>{console.log(res)uni.showToast({title:res.msg,icon:'none'})if(res.code==0){let userInfo = res.userInfouni.setStorageSync("token",userInfo.token)uni.setStorageSync("tokenExpired",userInfo.tokenExpired)this.userInfo = userInfo}})},sendEmail(type){this.req('emailCode',`email=${this.email}&type=${type}`).then(res=>{uni.showToast({title:res.msg,icon:'none'})})},loginEm(){this.req('loginByEmail',`email=${this.email}&code=${this.code}`).then(res=>{console.log(res)uni.showToast({title:res.msg,icon:'none'})if(res.code==0){let userInfo = res.userInfouni.setStorageSync("token",userInfo.token)uni.setStorageSync("tokenExpired",userInfo.tokenExpired)this.userInfo = userInfo}})},bindEm(){let tokens = uni.getStorageSync('token')this.req('bind',`username=${this.username}&email=${this.email}&code=${this.code}&token=${tokens}`).then(res=>{console.log(res)uni.showToast({title:res.msg,icon:'none'})})},unbindEm(){let tokens = uni.getStorageSync('token')this.req('unbind',`username=${this.username}&email=${this.email}&code=${this.code}&token=${tokens}`).then(res=>{console.log(res)uni.showToast({title:res.msg,icon:'none'})})}}}
</script><style>.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;}
</style>

测试

注册

在这里插入图片描述

登录

在这里插入图片描述

获取个人信息

在这里插入图片描述

绑定/解除绑定邮箱

在这里插入图片描述

邮箱验证码登录

没有绑定则邮箱非法
在这里插入图片描述

数据库状态

在这里插入图片描述
在这里插入图片描述
【本文正在参与“100%有奖|我的Serverless 实战”征稿活动】,活动地址:https://marketing.csdn.net/p/15940c87f66c68188cfe5228cf4a0c3f

这篇关于我的 Serverless 实战—SCF构建小型服务端并结合uni-app的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/613856

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Python结合requests和Cheerio处理网页内容的操作步骤

《Python结合requests和Cheerio处理网页内容的操作步骤》Python因其简洁明了的语法和强大的库支持,成为了编写爬虫程序的首选语言之一,requests库是Python中用于发送HT... 目录一、前言二、环境搭建三、requests库的基本使用四、Cheerio库的基本使用五、结合req

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

macOS怎么轻松更换App图标? Mac电脑图标更换指南

《macOS怎么轻松更换App图标?Mac电脑图标更换指南》想要给你的Mac电脑按照自己的喜好来更换App图标?其实非常简单,只需要两步就能搞定,下面我来详细讲解一下... 虽然 MACOS 的个性化定制选项已经「缩水」,不如早期版本那么丰富,www.chinasem.cn但我们仍然可以按照自己的喜好来更换

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2