我的 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

相关文章

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2