我的 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与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

Java实战之利用POI生成Excel图表

《Java实战之利用POI生成Excel图表》ApachePOI是Java生态中处理Office文档的核心工具,这篇文章主要为大家详细介绍了如何在Excel中创建折线图,柱状图,饼图等常见图表,需要的... 目录一、环境配置与依赖管理二、数据源准备与工作表构建三、图表生成核心步骤1. 折线图(Line Ch

Java使用Tesseract-OCR实战教程

《Java使用Tesseract-OCR实战教程》本文介绍了如何在Java中使用Tesseract-OCR进行文本提取,包括Tesseract-OCR的安装、中文训练库的配置、依赖库的引入以及具体的代... 目录Java使用Tesseract-OCRTesseract-OCR安装配置中文训练库引入依赖代码实

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程

《在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程》本文介绍了在Java中使用ModelMapper库简化Shapefile属性转JavaBean的过程,对比... 目录前言一、原始的处理办法1、使用Set方法来转换2、使用构造方法转换二、基于ModelMapper

Java实战之自助进行多张图片合成拼接

《Java实战之自助进行多张图片合成拼接》在当今数字化时代,图像处理技术在各个领域都发挥着至关重要的作用,本文为大家详细介绍了如何使用Java实现多张图片合成拼接,需要的可以了解下... 目录前言一、图片合成需求描述二、图片合成设计与实现1、编程语言2、基础数据准备3、图片合成流程4、图片合成实现三、总结前

nginx-rtmp-module构建流媒体直播服务器实战指南

《nginx-rtmp-module构建流媒体直播服务器实战指南》本文主要介绍了nginx-rtmp-module构建流媒体直播服务器实战指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. RTMP协议介绍与应用RTMP协议的原理RTMP协议的应用RTMP与现代流媒体技术的关系2

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

Golang操作DuckDB实战案例分享

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