基础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//字段