node.js实现简单登录注册功能

 更新时间:2022年04月26日 14:57:21   作者:前端攻城fff  
这篇文章主要为大家详细介绍了node.js实现简单登录注册功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了node.js实现简单登录注册的具体代码,供大家参考,具体内容如下

1、首先需要一个sever模块用于引入路由,引入连接数据库的模块,监听服务器
2、要有model层,里面写数据库连接模块和数据库的各种model(表),并导出model对象
3、工具类utils,里面存放一些功能的模块,并且封装后导出 ,例如发送验证码的功能
4、写路由,需要对数据库操作就使用导出的model对象,需要功能模块就使用导出的功能对象
随后返回这个路由,在sever里引入
5、生成api文档

sever模块

//实现登录注册,要先自己写路由放在本地的服务器上
const express=require('express');
//登录注册需要连接到服务器,连接的逻辑单独为一个db包,这里面放着和数据库有关的,比如说数据库的表,数据库的连接
//这里只需要引入连接上述包的连接模块即实现连接
const db=require('./db/connect');

//实例化express模块,这里的实例化对象就是用来操作路由啊使用中间件之类的,都是它
const app=express();

//引入解析请求体的中间件模块,方便路由里可以直接使用数据
const bodyparser=require('body-parser');
//使用这里面的解析请求体的方法
//这里use里面使用的是中间件模块的方法,所以里面是点---------
app.use(bodyparser.urlencoded({extended:false}))
app.use(bodyparser.json())


//下面就是连接路由,先去写下路由,之后在那里导出,这里就可以连接到了
//router里面存放的是全部的不同的路由
//在使用路由之前需要引入能解析请求体的中间件
//引入路由
const userRouter=require('./router/userRouter')
app.use('/user',userRouter);


//开启端口号为3000的本地服务器
app.listen(3000,()=>{
    console.log("服务器已开启");


})

数据库model包

1.根目录下的数据库连接

//这个模块不需要导出什么,其他地方引入这个模块就自动执行里面的代码,不需要返回的数据进行下一步操作
//因此不需要导出
const mongoose=require('mongoose');
mongoose.connect('mongodb://localhost/first');//连接到哪一个数据库
let db=mongoose.connection;//数据库连接后的对象,以便于后续对连接过程的监听
db.on("error",console.error.bind(console,"连接异常"));
db.once("open",()=>{
    console.log("连接成功");
})

2.model模块(表)

//对数据库操作,需要mongoose模块
const mongoose=require('mongoose');

//由于前面已经连接到数据库了,这里就可以直接创建schema对象了
const userSchema=mongoose.Schema({
    us:{type:String,required:true},
    ps:{type:String,required:true},
    age:Number,
    sex:{type:Number,default:0}
})

//这里需要对上面创建的表头(字段)集合转化为模型,即集合为一张表
//并返回一个对象,方便后续对表的操作,这里的对象需要导出,方便在其他模块使用
//这里导出,是为了在路由里使用这个对象对数据库进行操作
const User=mongoose.model("users",userSchema);//使用model方法转化,第一个参数是表名,第二个参数是需要转化的模型
module.exports=User;

工具类utils

//utils是工具类的包,那么发送邮件的程序算是一个工具
//这里将发送的方法封装并导出
const nodemailer=require('nodemailer');

//使用node方法创建发送的对象,接下来发送的方法肯定是该对象操作的
//创建发送对象基本都是固定格式
let transporter=nodemailer.createTransport({
    host:"smtp.qq.com",//发送方使用的邮箱
    port:465,//端口号,可以在lib/well-known/service.json下找到这些信息
    secure:true,
    auth:{
        user:"1507337624@qq.com",
        pass:""   //这里不是邮箱密码,而是邮箱开始第三方发送时给的验证码
    }
})

//这里将发送的方法封装,因为只需要导出这个方法,其他并不需要导出

function send(mail,code){
    //邮件信息
    let mailContent={
        from:'<1507337624@qq.com>',
        to:mail,
       subject:"验证码 ",
       text:`您的验证码是$[code],有效期五分钟`
    }
    //这里的发送是异步的,发送成功与否只有回调函数里才知道,那么总不能发送成功后的代码都写在这个工具里吧
    //这只是个工具类,发送成功和失败返回就行,谁用就谁处理
    //那么返回回调函数的失败或者成功就要promise对象了,这里直接给发送的结果返回一个promise对象
    return new Promise((resolve,reject)=>{
        transporter.sendMail(mailContent,(err,data)=>{
            //错误优先,err默认为null,另一个参数data包含了发送的一系列信息,状态,数据之类
            if(err){
                //执行reject就意味着错误,promise就会走catch
                reject()
            }else{
                resolve()
            }
        })
    })
}
module.exports={send}//这里返回的是一个对象,里面有一个属性是send,而不是直接返回send方法本身,其实两者都可以,但是规范上来说更多的是这个

核心路由router

这里写接收并且处理请求的具体方法

//创建一个路由就要先实例化express下创建路由的方法
const express=require('express');
const router=express.Router();//注意这里的router是方法,需要括号
//登录注册等需要对数据库进行操作,这里需要对应的model,先去创建一个model
//创建好了,可以引入了
const User=require("../db/model/userModel");

//注册还需要邮箱验证,那么邮箱验证是一个单独的功能,也就是需要实现的工具类的功能
//所以需要单独一个包存放工具类功能,之后需要的时候引入就可以了,这里先去写
//好了写完了,下面可以导入了
const Mail=require('../utils/mail');
//那么问题来了,导入之后在哪里调用,发送邮箱验证码也是一个请求吧
//既然是请求就应该有对应的接口,因为毕竟是在用户注册上请求发送验证码,所以归在用户路由下

//创建一个全局变量用于保存验证码信息,和注册的邮箱是对应的,因此这个变量是对象,注册的邮箱作为属性
const mailCodes={}

//接下来就可以写路由的接口了
//
//注册接口,生成 接口文档
/**
 * @api {post} /user/register 用户注册
 * @apiName 用户注册
 * @apiGroup User
 *
 * @apiParam {String} us 用户名
 * @apiParam {String} ps 密码
 * @apiParam {String} mailCode 验证码
 *
 * @apiSuccess {String} firstname Firstname of the User.
 * @apiSuccess {String} lastname  Lastname of the User.
 */
//这里需要对post请求的body分析,需要body-parser中间件,
//但是这里只返回给serve路由 ,因此要在server层引入
router.post('/register',(req,res)=>{
    let{us,ps,mailCode}=req.body;

    //先判断us和ps还有验证码是否都输入了,如果没输入完成直接就终止执行
    if(!us||!ps||!mailCode)return res.send({err:-1,msg:"参数错误"})

    //将保存的验证码对应的us属性的值与传来的验证码比较,不对的话直接就终止了,不需要再往下进行了
    if(mailCodes[us]!=mailCode)return res.send({err:-4,msg:"验证码不正确"})

    //接下来需要判断用户名是否存在,不存在的话就可以注册
    User.find({us})
        .then((data)=>{
            //只要去找了,就会返回数据,没找到返回空,否则返回找到的数据
            if (data.length==0){
                //没有的话就可以注册了,那么下一步操作也是需要返回promise对象,方便链式调用
                //这里涉及到对数据库的操作,需要引入数据库的model,在顶部引入
               return  User.insertMany({us,ps})
            }else{
                //如果存在的话就不能注册,那么就需要返回错误信息
                return res.send({err:-3,msg:"该用户名已存在"})
            }
        })
        //之前说过对数据库的操作默认返回一个promise对象,可以直接then,catch
        //复习一下对数据库操作返回的promise是内部定义的,then里面回调参数是data,即查询或者插入的数据之类
        //而catch里面的参数err就是错误信息
        .then(()=>{
            //这里的res.send是像前台返回的信息,前面路由创建的学习说过了
            res.send({err:0,msg:"注册ok"})
        })
        //无论是几个链式调用,只要有异常都会来到这里
        .catch((err)=>{
            //这里的错误不是注册过程中重复不能注册的错误,这里应该是数据库连接异常的错误这类
            res.send({err:-1,msg:"内部错误"})
        })

})

//登录接口,接口文档
/**
 * @api {post} /user/login  用户登录
 * @apiName 用户登录
 * @apiGroup User
 *
 * @apiParam {String} us 用户名
 * @apiParam {String} ps 密码
 *
 * @apiSuccess {String} firstname Firstname of the User.
 * @apiSuccess {String} lastname  Lastname of the User.
 */
router.post("/login",(req,res)=>{
    let{us,ps}=req.body;

    //先判断us和ps还有验证码是否都输入了,如果没输入完成直接就终止执行
    if(!us||!ps)return res.send({err:-1,msg:"参数错误"})


        //下面的find直接就在数据库里寻找了,找到了返回数据,否则返回空(都是一个数组)
        User.find({us,ps})
        .then((data)=>{
            //如果找到了,则data的长度大于0,反之是没找到
            if(data.length>0){
                res.send({err:0,msg:"登录 OK"})
            }else{
                res.send({err:-1,msg:"用户名或密码错误"})
            }
        })
        .catch((err)=>{
            res.send({err:-2,msg:"内部错误"})
        })

})

//接口文档
/**
 * @api {post} /user/getCode  获取验证码
 * @apiName 获取验证码
 * @apiGroup User
 *
 * @apiParam {String} us 用户名
 *
 * @apiSuccess {String} firstname Firstname of the User.
 * @apiSuccess {String} lastname  Lastname of the User.
 */
//为什么会在这里写一个发送邮箱验证码的接口,它原本是一个方法,
// 但是请求后台发送一个验证码,并且传入需要发送的邮箱,这本身就是一个完整的请求
//想一下,我在页面上注册的时候,输入邮箱后点击发送验证码,这不是一个请求吗,那不就需要一个接口吗
router.post('/getCode',(req,res)=>{
    let {us}=req.body;//从请求体中找到需要发送的地址
    //这里利用随机函数生成随机数
    //强转为整数,这里之所以用变量保存起来,是因为下面需要将验证码和发送的对象一起保存
    //发送对象作为属性,验证码为值,因为后续需要比较验证码,所以需要一个全局变量来保存,去上面创建
    let code=parseInt(Math.random()*10000)
    Mail.send(us,code)
        .then(()=>{
            //发送成功要返回信息,并且保存验证码
            //验证码一定在发送成功后保存,否则随便输入一个不管发送成功还是失败都保存的话会大量占用空间
            res.send({err:0,msg:"验证码发送成功"})
            mailCodes[us]=code;//将邮箱和验证码一一对应保存起来,方便其他接口的比较
        })
        .catch(()=>{
            res.send({err:-3,msg:"发送失败,请检查邮箱是否正确或网络连接"})
        })

})
//路由写完了,现在可以把该数据库返回到操作层了
module.exports=router;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Electron架构深入探究

    Electron架构深入探究

    这篇文章主要为大家介绍了Electron架构深入探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • node.js中的http.response.addTrailers方法使用说明

    node.js中的http.response.addTrailers方法使用说明

    这篇文章主要介绍了node.js中的http.response.addTrailers方法使用说明,本文介绍了http.response.addTrailers的方法说明、语法、接收参数、使用实例和实现源码,需要的朋友可以参考下
    2014-12-12
  • pnpm的安装及其使用教程(汇总)

    pnpm的安装及其使用教程(汇总)

    pnpm是 Node.js 的替代包管理器,它是 npm 的直接替代品,速度更快、效率更高,它由 npm/yarn 衍生而来,但却解决了 npm/yarn 内部潜在的 bug,并且极大了地优化了性能,本文给大家介绍pnpm的安装及其使用,感兴趣的朋友一起看看吧
    2023-12-12
  • 在Ubuntu上安装最新版本的Node.js

    在Ubuntu上安装最新版本的Node.js

    Node.js是一个软件平台,通常用于构建大规模的服务器端应用。Node.js使用JavaScript作为其脚本语言,由于其非阻塞I/O设计以及单线程事件循环机制,使得它可以交付超高的性能。
    2014-07-07
  • 基于Node.js实现一键生成个性化二维码

    基于Node.js实现一键生成个性化二维码

    这篇文章主要为大家详细介绍了如何使用Node.js、Jimp和QRCode库,结合一个简单的脚本,通过命令行命令来快速给二维码加上指定的背景,打造更有个性化的二维码,感兴趣的可以了解下
    2024-03-03
  • 在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法

    在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法

    这篇文章主要介绍了在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • 一文详解node.js有哪些全局对象呢

    一文详解node.js有哪些全局对象呢

    这篇文章主要介绍了一文详解node.js有哪些全局对象呢,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2022-09-09
  • 什么是MEAN?JavaScript编程中的MEAN是什么意思?

    什么是MEAN?JavaScript编程中的MEAN是什么意思?

    这篇文章主要介绍了什么是MEAN?JavaScript编程中的MEAN是什么意思?,跟lampp一样,MEAN是指现代web应用全栈开发工具一个组合,需要的朋友可以参考下
    2014-12-12
  • window系统管理多版本node的实现

    window系统管理多版本node的实现

    存在不同项目使用npm时所需要的版本不一致,又不想每次都卸载又重新安装node,这时候就需要多版本管理器,本文主要介绍了window系统管理多版本node的实现,感兴趣的可以了解一下
    2024-02-02
  • 你所未知的3种Node.js代码优化方式

    你所未知的3种Node.js代码优化方式

    这篇文章主要为大家介绍了3种你所未知的Node.js代码优化方式,帮助大家刚好的进行代码优化,感兴趣的小伙伴们可以参考一下
    2016-02-02

最新评论