基础api项目

1、导入基础组件

安装组件

//初始化包管理配置文件
npm init -y
//安装express
npm i express
//安装cors 跨域
npm i cors
//安装mysql
npm i mysql
//安装bcryptjs加密
npm i bcryptjs
//安装数据验证模块定义验证规则
npm i joi
//自动对表单数据进行验证的功能
npm i @escook/express-joi
//安装生成 Token 字符串的包
npm i jsonwebtoken
//安装解析 Token 的中间件
npm i express-jwt

导入组件

const express = require('express')
const app = express()
const cors =require('cors')

注册中间件

//cors跨域
app.use(cors())
//解析格式的表单数据的中间件
app.use(express.urlencoded({ extended: false }))

优化 res.send() 代码

// 响应数据的中间件,一定要在路由之前,封装 res.cc 函数
app.use(function (req,res,next){
    res.cc = (err,status = 1)=>{
        res.send({
            status,
            message: err instanceof Error ? err.message : err,
        })
    }
    next()
})

//使用方式
return res.cc(err)
return res.cc('注册用户失败,请稍后再试')
res.cc('注册成功', 0)

导入路由注册

//路由导入并注册
const userRouter = require('./router/user')
app.use('/api',userRouter)

路由配置

const express = require('express')
const router = express.Router()
//导入用户处理函数模块
const userHandler = require('../router_handler/user')

//注册新用户
router.post('/reguser',userHandler.regUser)
//登录
router.post('/login',userHandler.login)


module.exports = router

路由函数

// 导入数据库操作模块
const db = require('../db/index')
//导入bcryptjs加密
const bcrypt = require('bcryptjs')

//注册用户的处理函数
exports.regUser = (req,res) => {
    const userinfo = req.body
    //判断注册信息不能为空
    if(!userinfo.username || !userinfo.password){
        return res.cc('用户名或密码不能为空')
    }
    //查询用户名是否被占用
    const sqlStr = 'select * from xo_users where username=?'
    db.query(sqlStr, userinfo.username, (err, results) => {
        if(err){
            return res.cc(err)
        }
        if (results.length > 0) {
            return res.cc('用户名被占用,请更换其他用户名!')
        }
        //加密密码
        userinfo.password = bcrypt.hashSync(userinfo.password,10)
        //定义插入新用户的 SQL 语句
        const sql = 'insert into xo_users set ?'
        db.query(sql,{ username:userinfo.username,password:userinfo.password},(err,results)=>{
            if(err)return res.cc(err)
            if (results.affectedRows !== 1) {
                return res.cc('注册用户失败,请稍后再试')
            }
            //注册成功
            res.cc('注册成功', 0)
        })
    })
    
}
//登录的处理函数
exports.login = (req,res) => {
    res.send('登录okk')
}

db目录中mysql封包

const mysql = require('mysql')
//配置数据库
const db = mysql.createPool({
    host: '127.0.0.1',
    port:'3306',
    user: 'root',
    password: '******',
    database: 'api_xo',
})

module.exports = db

bcryptjs加密用法

//导入bcryptjs加密
const bcrypt = require('bcryptjs')
//路由函数
exports.regUser = (req,res) => {
    const userinfo = req.body
    //加密req.body包含在POST请求中的实体password数据
    userinfo.password = bcrypt.hashSync(userinfo.password,10)
 
    
}

//密码比较bcrypt.compareSync
const compareResult = bcrypt.compareSync(userinfo.password, results[0].password)

//bcrypt有关的内置函数:
//bcrypt.compare	   异步函数比较
//bcrypt.compareSync   同步函数比较
//bcrypt.compareResult 返回布尔值
bcrypt.compare(password1, password2):将两个密码进行比较,并返回比较结果。
bcrypt.compareSync(password1, password2):将两个密码进行比较,并在比较完成后返回比较结果。
bcrypt.compareResult(password1, password2):将两个密码进行比较,并返回比较结果。该函数不会阻塞主线程,而是会在后台线程中进行比较处理。


bcrypt.compare和bcrypt.compareSync都接受两个字符串参数,分别是待比较的两个密码。这两个函数的主要区别在于它们的处理方式。bcrypt.compare是异步函数,它将在一个后台线程中比较两个密码,而bcrypt.compareSync则是同步函数,它会阻塞主线程直到比较完成。

bcrypt.compareResult是一个布尔值,用于指示比较是否成功。它与bcrypt.compare和bcrypt.compareSync不同,因为它只接受一个参数——待比较的两个密码。它的用途是在比较完成后返回一个比较结果,而不是等待比较完成。

总的来说,这三个函数都是用于比较两个密码的,但是它们的使用方法和功能略有不同。如果您需要比较多个密码,或者需要在比较过程中保持线程安全,那么您可以选择使用bcrypt.compareSync。如果您需要异步比较,或者需要在比较过程中动态调整线程优先级,那么您可以选择使用bcrypt.compare。如果您只需要比较两个密码,并且不介意等待比较完成,那么您可以选择使用bcrypt.compareResult。


数据验证

//---验证规则模块里文档----
const joi = require('joi')

/**
 * string() 值必须是字符串
 * alphanum() 值只能是包含 a-zA-Z0-9 的字符串
 * min(length) 最小长度
 * max(length) 最大长度
 * required() 值是必填项,不能为 undefined
 * pattern(正则表达式) 值必须符合正则表达式的规则
 * integer()  验证一个输入是否为正整数
 */

// 用户名的验证规则
const username = joi.string().alphanum().min(1).max(10).required()
// 密码的验证规则
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required()

// 注册和登录表单的验证规则对象
exports.reg_login_schema = {
  // 表示需要对 req.body 中的数据进行验证
  body: {
    username,
    password,
  },
}

//--------------------------------------------------------
//-----路由文档----
// 1. 导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')
// 2. 导入需要的验证规则对象
const { reg_login_schema } = require('../schema/user')

// 注册新用户
// 3. 在注册新用户的路由中,声明局部中间件,对当前请求中携带的数据进行验证
// 3.1 数据验证通过后,会把这次请求流转给后面的路由处理函数
// 3.2 数据验证失败后,终止后续代码的执行,并抛出一个全局的 Error 错误,进入全局错误级别中间件中进行处理
router.post('/reguser', expressJoi(reg_login_schema), userHandler.regUser)


//--------------------------------------------------------
//-----在 `app.js` 的全局错误级别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户端
const joi = require('joi')

// 错误中间件
app.use(function (err, req, res, next) {
  // 数据验证失败
  if (err instanceof joi.ValidationError) return res.cc(err)
  // 未知错误
  res.cc(err)
})

token认证

配置文件

module.exports = {
    // 加密和解密 Token 的秘钥
    jwtSecretKey: 'itheima No22. ^_^',
    // token 的有效期10小时
    expiresIn: '10h',
  }

生成JWT的token字符串

// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')
// 导入配置文件
const config = require('../config')


//在服务器端生成 Token 的字符串
const user = { ...results[0], password: '', user_pic: '' }
//对用户信息进行加密,生成token字符串
const tokenStr = jwt.sign(user,config.jwtSecretKey,{ expiresIn: config.expiresIn})
//登录成功
res.send({
   status: 0,
   message: '登录成功!',
   token: 'Bearer ' + tokenStr,
})

解析 Token 的中间件

// 一定要在路由之前配置解析 Token 的中间件
// 导入配置文件
const config = require('./config')

// 解析 token 的中间件
const expressJWT = require('express-jwt')

// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT.expressjwt({ secret: config.jwtSecretKey, algorithms: ["HS256"] }).unless({ path: [/^\/api\//] }))

其他

//results.affectedRows是一个内置函数,用于返回最近一次执行INSERT、UPDATE或DELETE语句时修改的行数。换句话说,results.affectedRows表示当前事务对数据库进行了多少个修改操作。
if (results.affectedRows !== 1){
    return res.send('单条写入信息获取失败')
}

内置函数

results.length //将会是查询返回的行数
results.affectedRows  //将会是受影响的行数返回
results.first()//函数可以返回查询结果集中的第一行数据
results.forEach()//函数可以用来遍历查询结果集中的每一行数据
results[0].username//字段
游荡时间:
到此一游: xoxu