【node.js后台api项目】(二)实现注册功能

一、实现思路

注册功能简单来说就是提供一个路由,命中路由后把用户名和密码插入数据库。但是也有一些细节需要注意

  • 对前端传过来的值需要先进行合法性校验。
  • 规定用户名必须唯一,因此在往数据库插入用户信息前需要先检查用户名是否存在,若存在则响应客户端告知更改用户名。
  • 考虑到密码的安全性,我们不直接将密码明文保存在数据库,而是加密以后再存入数据库,可以利用一些第三方的npm包来实现这个需求。
  • 我们可以直接在 a p p app app上挂在路由,但是考虑到我们将来要书写众多的路由,我们可以把路由抽离出来,使用express.Router()得到router对象,在 r o u t e r router router对象上挂在路由,然后再通过app.use()使用该路由对象,从而实现模块化开发。

二、项目目录

项目目录结构如下
---- api_server
    ---- router
        ---- user.js
    ---- router_handler
      ---- user.js
    ----app.js
    ---- schema
        ---- user.js
router里存放路由关系,router_handler里存放路由处理函数。
schema用于放置数据校验规则的配置文件。

三、代码编写

1、基本代码

    ---- router
        ---- user.js

const express = require('express')
// 导入路由处理函数
const userHandler = require('../router_handler/user.js')
//调用express.Router()方法,该方法返回一个对象
const router = express.Router()


// 注册路由
router.post('/register', userHandler.register)

module.exports = router

    ---- app.js

// 导入user路由
const userRouter = require('./router/user.js')
// 使用路由,当第一个参数传入一个路由前缀时,会给所有userRouter上的路由路径加上该前缀,即我们访问的是 /api/login、/api/register
app.use('/api', userRouter)

    ---- router_handler
        ---- user.js

const register = (req , res) => {
	res.send('命中注册路由!')
}

module.exports = {
	login
}

到了这一步,我们可以先使用postman等 a p i api api测试工具,访问 http://127.0.0.1/api/login,如果成功返回 命中注册路由 , 说明接口已经跑通,可以进行接下来的编写了。

2、数据合法性校验

这一步我们通过 req.body(express.urlencoded解析数据后挂在在req.body上的)可以拿到前端传过来的数据,最简单的就是使用 if...else...判断使得用户名和密码符合我们的要求。

const register = (req, res) => {
  const userInfo = req.body
  if(!userInfo.username || !userInfo.password) return res.send({status: 1 , message: '注册失败!'})
  //其他的条件...
}

上面只是一个示例,验证了用户名或密码为空的情况,但是还有很多其他的校验还没做,如果都用 if...else...进行判断,代码冗余,可读性变差,因此我们可以借助一些第三方的包来做这个功能。
这里使用joi这个包来实现数据校验功能。

// ./schema/user.js
// 导入joi包用于数据校验
const Joi = require('joi')

// 定义登录注册的校验规则
const reg_login_schema = {
  //string()字符串,alphaum()数字和字母的组合,
  //min(1)长度最小为1,max(10)最大为10,required()这个值是必须有的
  username: Joi.string().alphanum().min(1).max(10).required(),
  password: Joi.string()
    .pattern(/^[\S]{6,12}$/)
    .required()
}

上面的代码导入了 j o i joi joi这个包,然后定义了一个对象,该对象里分别对用户名和密码做出一些约束。
由于登录和注册都需要对用户名密码进行合法性校验,所有我们可以封装一个自定义的中间件。

// ./schema/user.js
// 定义登录注册数据校验中间件
const joiExpress = (req, res, next) => {
  //根据文档使用Joi即可
  const schema = Joi.object(reg_login_schema)
 
  const userInfo = req.body ? req.body : {}
  //当匹配成功时,err的值是undefined
  const { error } = schema.validate(userInfo)
  if (error) res.cc(error)
  //自定义中间件一定记得调用next()方法,否则服务可能会在这里停止
  next()
}

// 导出该中间件
module.exports = joiExpress
// ./router/user.js
// 导入自定义的登录注册数据校验中间件
const joiExpress = require('../schema/user')

// 在该路由下使用中间件
router.post('/register', joiExpress, userHandler.register)

3、注册路由处理函数

基本代码如下

// ./router_handler/user.js
// 注册路由处理函数
const register = (req, res) => {
  const userInfo = req.body
  
  // 检查用户名是否已存在
  let sql = `select * from ${usersTable} where username=?`
  db.query(sql, [userInfo.username], (err, result) => {
    if (err) return res.send({status: 1 , message: err.message})
    if (result.length > 0) return res.send({status: 1 , message: '用户名已存在,请更换用户名!'})
    
    // 执行注册操作
    let insertSql = `insert into ${usersTable} set ?`
    // 将用户信息存入数据库
    db.query(insertSql, { username: userInfo.username, password: userInfo.password }, (err, result) => {
      if (err) return res.cc(err)
      if (result.affectedRows >= 1) res.send({status: 1 , message: '用户名已存在,请更换用户名!'})
      else res.send({status: 1 , message: '注册失败!请稍后重试~'})
    })
  })
}

上面的代码我们重复书写了很多次res.send(),且返回的数据对象有统一的格式,因此我们可以再进行一层封装,编写一个自定义中间件。

// ./app.js

// 自定义处理错误中间件
app.use((req, res, next) => {
 //在res对象上挂载cc函数,之后的req上都会拥有该cc函数
  res.cc = (err, status = 1) => {
    err = err instanceof Error ? err.message : err
    res.send({
      status,
      message: err
    })
  }
  next()
})

// 使用路由,上面的中间件必须在下面这一行挂在路由的前面引入
app.use('/api', userRouter)

有了这个中间件,将代码更改一下

// ./router_handler/user.js

const register = (req, res) => {
  const userInfo = req.body
  // 检查用户名是否已存在
  let sql = `select * from ${usersTable} where username=?`
  db.query(sql, [userInfo.username], (err, result) => {
    if (err) return res.cc(err)
    if (result.length > 0) return res.cc('用户名已存在,请更换用户名!')
    // 执行注册操作
    let insertSql = `insert into ${usersTable} set ?`
    // 将用户信息存入数据库
    db.query(insertSql, { username: userInfo.username, password: userInfo.password }, (err, result) => {
      if (err) return res.cc(err)
      if (result.affectedRows >= 1) res.cc('注册成功!', 1)
      else res.cc('注册失败,请稍后重试~')
    })
  })
}

4、密码加密

// ./router_handler/user.js

// 导入bcryptjs用于密码加密
const bcrypt = require('bcryptjs')

// 注册路由处理函数
const register = (req, res) => {
  const userInfo = req.body
  // 检查用户名是否已存在
  let sql = `select * from ${usersTable} where username=?`
  db.query(sql, [userInfo.username], (err, result) => {
    if (err) return res.cc(err)
    if (result.length > 0) return res.cc('用户名已存在,请更换用户名!')
    // 执行注册操作
    let insertSql = `insert into ${usersTable} set ?`
    
    // 将明文密码进行加密
    userInfo.password = bcrypt.hashSync(userInfo.password, 10)
    
    // 将用户信息存入数据库
    db.query(insertSql, { username: userInfo.username, password: userInfo.password }, (err, result) => {
      if (err) return res.cc(err)
      if (result.affectedRows >= 1) res.cc('注册成功!', 1)
      else res.cc('注册失败,请稍后重试~')
    })
  })
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端corner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值