文章目录
初始化.js项目
1.创建项目
- 应用系统定制开发创建项目文件夹,应用系统定制开发并再项目根目录初始化
npm应用系统定制开发包管理文件,以ExpressServer为例,代码如下:
mkdir ExpressServer && cd ExpressServernpm init -y- 1
- 2
- 应用系统定制开发应用系统定制开发运行如下命令安装
express:
npm i express- 1
- 应用系统定制开发创建项目入口文件,应用系统定制开发并初始化内容如下:
//1. 导入express模块const express = require('express')//2. 创建express应用系统定制开发服务器实例const server = express()// TODO:应用系统定制开发在这里编写服务器代码//3. 应用系统定制开发监听服务器80端口server.listen(80, () => { console.log('Express server running on http://127.0.0.1:80')})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.配置cors跨域
- 运行如下命令安装
cors中间件:
npm i cors- 1
- 在
app.js应用系统定制开发中导入并配置cors中间件:
//1. 导入cors中间件const cors = require('cors')//2. 注册cors中间件server.use(cors())- 1
- 2
- 3
- 4
3.应用系统定制开发配置数据解析中间件
- 应用系统定制开发配置如下代码,解析
application/x-www-form-urlencoded格式的表单数据:
server.use(express.urlencoded({ extended: false }))- 1
4.初始化路由文件夹
- 项目根目录中,创建
router文件夹,用于存放所有的路由模块 - 项目根目录中,创建
router_handler文件夹,用于存放所有的路由处理模块
mkdir router mkdir router_handler- 1
- 2
5.初始化路由模块
- 在
router文件夹中新建auth.js,用于存储所有的用户路由,编写内容如下:
const express = require('express')//创建路由对象const router = express.Router()//用户注册路由router.post('/register', (req, res) => { res.send('POST /register')})//用户登录路由router.post('/login', (req, res) => { res.send('POST /login')})//共享router对象module.exports = router- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 在
app.js中,导入并注册用户路由模块:
//导入用户路由const authRouter = require('./router/auth')//注册用户路由server.use('/api/auth',authRouter)- 1
- 2
- 3
- 4
6.启动并测试服务器
- 安装
nodemon模块,用于启动服务器(nodemon模块可以在我们修改代码后自动重启服务器):
npm i -g nodemon- 1
- 使用
nodemon模块启动服务器:
nodemon app.js- 1
如果操作正确,服务器正常启动,将输出如下内容:
PS E:\ExpressServer> nodemon .\app.js[nodemon] 2.0.16[nodemon] to restart at any time, enter `rs`[nodemon] watching path(s): *.*[nodemon] watching extensions: js,mjs,json[nodemon] starting `node .\app.js`Express server running on http://127.0.0.1:80- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 使用
postman测试接口是否配置正确,以POST方式分别访问localhost/api/auth/register和localhost/api/auth/login
7.抽离路由处理函数
为了保证路由模块的存粹性,将路由处理函数单独抽离出来放在
router_handler文件夹中
- 在
router_handler文件夹中创建并编辑auth.js文件如下:
//router_handler/auth.js//注册处理函数exports.authRegister = (req, res) => { res.send('POST /register')}//登录处理函数exports.authLogin = (req, res) => { res.send('POST /login')}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 修改
/router/auth.js文件代码如下:
//router/auth.jsconst express = require('express')//创建路由对象const router = express.Router()//引入auth处理模块const authHandler = require('../router_handler/auth')//用户注册路由router.post('/register', authHandler.authRegister)//用户登录路由router.post('/login', authHandler.authLogin)//共享router对象module.exports = router- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 使用
nodemon启动并使用postman访问localhost/api/auth/register和localhost/api/auth/login,会得到和之前(6.3)相同的结果。
注册
1.创建数据库
- 创建
MySql数据库,此处以db_node为例:
CREATE SCHEMA `db_node` ;- 1
如果还没有安装MySql,可以在这里下载
- 创建
t_users数据表,创建表sql指令如下:
CREATE TABLE `db_node`.`t_users` ( `id` INT NOT NULL AUTO_INCREMENT, `username` VARCHAR(255) NOT NULL, `password` VARCHAR(255) NOT NULL, `nickname` VARCHAR(255) NULL, `email` VARCHAR(255) NULL, `avatar` TEXT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE, UNIQUE INDEX `username_UNIQUE` (`username` ASC) VISIBLE)ENGINE = InnoDBDEFAULT CHARACTER SET = utf8mb4COLLATE = utf8mb4_0900_ai_ci;- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2.安装并配置mysql模块
- 执行如下指令,安装
mysql模块:
npm i mysql- 1
- 创建
/db/index.js文件,此文件用于存储数据库连接对象:
// db/index.js//导入mysql模块const mysql = require('mysql')//创建数据库连接对象const db = mysql.createPool({ host: '127.0.0.1', //数据库服务器地址,我们使用本机 user: 'root', //mysql用户名,替换为你的用户名 password: '000000', //mysql密码,替换为你的密码 database: 'db_node',//数据库名称,此处为db_node})//导出数据库连接对象module.exports = db - 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3.注册
- 注册步骤
- 检测表单数据
- 检测用户名是否占用
- 密码加密处理
- 插入新用户
- 检测表单数据
const userinfo = req.body if(!userinfo.username || !userinfo.password){ return res.send({ status: 201, message:'用户名、密码不能为空!' }) }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 检测用户名是否占用
- 从
db/index.js导入db
const db = require('../db/index')- 1
- 定义
SQL
sqlStr = 'select * from t_users where username = ?'- 1
- 执行
SQL语句,判断是否占用:
db.query(sql, userinfo.username, (err, results) => { if (err) return res.send({ status: 201, message: err.message }) if(results.length > 0){ return res.send({status:201,message:'用户名已存在'}) } //TODO:插入新用户 })- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 密码加密
- 执行以下指令,安装
bcryptjs模块
npm i bcryptjs- 1
- 在
router_handler/auth.js中,导入bcryptjs
const bcrypt = require('bcryptjs')- 1
- 插入用户之前,使用
bcrypt.hashSync(password,len)进行加密
userinfo.password = bcrypt.hashSync(userinfo.password,10)- 1
- 插入用户
- 定义
SQL
sqlStr = 'insert into t_users set ?'- 1
- 执行
SQL,插入用户
db.query(sql, { username: userinfo.username, password: userinfo.password }, (err, results) => { if (err) return res.send({ status: 201, message: err.message }) if (results.affectedRows === 1) return res.send({ status: 200, message: 'success' }) return res.send({ status: 201, message: '注册失败,稍后再试' }) })- 1
- 2
- 3
- 4
- 5
- 6
4.注册测试
- 使用
PostMan发送注册信息,操作如下:
- 我们可以查看数据库:
如此,注册方法变成功执行了。
优化res.send()
我们在代码中多次使用到了
res.send()方法,非常繁琐,需要封装简化代码。(不优化也没啥)
- 在
app.js中所有的路由之前定义并注册全局中间件
server.use((req, res, next) => { //status = 200 success //status = 201 failure res.cc = function (err, status = 1) { res.send({ status: status, message: err instanceof Error ? err.message : err, }) } next()})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
这样在所有的路由中,res都具有一个cc方法,可以方便的向客户端输出结果。
优化
表单验证,前端为辅,后端为主,永远不相信前端提交的数据
1.安装包
1.安装joi包,为表单项定义验证规则
npm i joi- 1
- 安装
@escook/express-joi,实现自动验证表单数据
npm i @escook/express-joi- 1
2.验证规则
- 新建
schema/auth.js用户验证规则模块
mkdir schematouch schema/auth.js- 1
- 2
- 初始化如下:
//schema/auth.js//导入包const joi = require('joi')/** * string() 字符串 * alphanum() 字符数字串 * min(len) 最短 * max(len) 最长 * required() 不为空 * pattern(reg) 符合正则 *///用户名密码验证规则const username = joi.string().alphanum().min(1).max(10).required()const password = joi.string().pattern(/^[\S]{6,12}$/).required()//登录注册验证对象exports.reg_login_schema = { body: { username, password }}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
4.插入验证中间件
- 引入验证中间件
//引入验证中间件const expressJoi = require('@escook/express-joi') //(*)- 1
- 2
- 引入验证规则
//引入验证规则const { reg_login_schema } = require('../schema/auth')//(*)- 1
- 2
- 注册验证中间件
//用户注册路由,添加验证中间件router.post('/register', expressJoi(reg_login_schema), authHandler.authRegister) //(*)- 1
- 2
修改后的route/auth.js,如下:
//router/auth.jsconst express = require('express')//创建路由对象const router = express.Router()//引入验证中间件const expressJoi = require('@escook/express-joi') //(*)//引入验证规则const { reg_login_schema } = require('../schema/auth')//(*)//引入auth处理模块const authHandler = require('../router_handler/auth')//用户注册路由,添加验证中间件router.post('/register', expressJoi(reg_login_schema), authHandler.authRegister) //(*)//用户登录路由router.post('/login', authHandler.authLogin)//共享router对象module.exports = router- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
注意以上代码中(*)处是修改的地方。
5.捕获验证错误
在app.js中创建并注册全局错误处理中间件,用于处理验证错误(也可以处理其他错误)。
- 引入验证规则
//引入验证规则模块const joi = require('joi')- 1
- 2
- 创建并注册全局异常中间件
//引入验证规则模块const joi = require('joi')//注册异常捕获中间件server.use((err, req, res, next) => { if (err instanceof joi.ValidationError) return res.cc(err) res.cc(err)})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
6.验证测试
登录
1.登录步骤
- 表单验证;
- 数据查询;
- 密码比较;
- 生成
JWT的Token字符串
2.表单验证
- 修改
router/auth.js的路由如下:
//用户登录路由router.post('/login', expressJoi(reg_login_schema), authHandler.authLogin)- 1
- 2
3.数据查询
在router_handler/auth.js中的登录处理方法中:
- 表单数据接收
const userinfo = req.body- 1
- 定义
SQL语句
const sqlStr = 'select * from t_users where username=?'- 1
- 执行查询
SQL
//执行查询db.query(sqlStr, userinfo.username, (err, results) => { //查询失败 if (err) return res.cc(err) //查询结果不合理 if (results.length !== 1) return res.cc("登录失败") //TODO:判断密码})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4.密码比较
调用
bcrypt.compreSync(表单密码,数据库密码)判断密码是否一致,true一致,false不一致
//判断密码const cmpRes = bcrypt.compare(userinfo.password, results[0].password)if (!cmpRes) return res.cc('Login Failed')//TODO:登录成功,生成token- 1
- 2
- 3
- 4
- 5
5.生成token
- 从查询结果中剔除
password和avatar两个值
const usr = { ...results[0], password: '', avatar: '' }- 1
- 安装
jwt
npm i jsonwebtoken- 1
- 在
router_handler/auth.js中导入jwt
const jwt = require('jsonwebtoken')- 1
- 根目录创建配置文件
config.js,并共享jwtSecretKey字符串(用于加密)
//config.jsmodule.exports = { //一个复杂字符串 jwtSecretKey: "alkjflasngaoieakgbnasdfzxfgasdf", expiresIn: '24h',//token有效期24h}- 1
- 2
- 3
- 4
- 5
- 6
- 加密用户信息,生成
token
//导入configconst config = require('../config')//生成tokenconst tokenStr = jwt.sign(usr, config.jwtSecretKey, { expiresIn: config.expiresIn,//token有效期为24小时})- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 返回客户端
res.send({ status: 200, message: 'login success', token: 'Bearer ' + tokenStr})- 1
- 2
- 3
- 4
- 5
- 测试登录
6.Token解析
- 安装
express-jwt模块(注意版本,较新版本不适合本教程)
npm i express-jwt@5.3.3- 1
app.js中注册路由之前配置Token中间件
const config = require('./config')//导入token中间件const expressJWT = require('express-jwt')//注册token中间件,所有以/api开头的路由都不需要验证token的正确性server.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/api\//] }))- 1
- 2
- 3
- 4
- 5
- 6
- 7
app.js中token认证失败异常捕捉
if (err.name === 'UnauthorizedError') return res.cc('认证失败')- 1
- 解析验证
访问非/api开头的路由即可,这里使用/my
想要验证成功,需要在Header中加入Authorization字段,字段的值是登录时返回的Token:
获取用户信息
用户中心功能的一部分,获取用户个人信息,使用/my/info路由的GET请求。
1.基本步骤
- 初始化个人中心路由“router/my.js”
- 初始化路由处理函数“router_handler/my.js”
- 获取用户信息
2.初始化/router/my.js
- 创建文件
router/my.js,编辑代码如下:
// 引入express模块const express = require('express')//创建路由对象const router = express.Router()//挂接/info路由router.get('/info', (req, res) => { res.send('ok')})//向外分享路由对象module.exports = router- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 在
app.js中导入当前路由模块(可以紧贴/api/auth路由向后写)
//导入路由const myRouter = require('./router/my')//注册/my路由server.use('/my', myRouter)- 1
- 2
- 3
- 4
3.测试路由配置
- 访问
/api/auth/login登录并获取token
复制返回的token字符串。
- 访问
/my/info
如果你和我的编码相同,返回ok即为正确。
4.初始化/router_handler/my.js
- 新建
/router_handler/my.js文件,编辑内容如下:
//暴露/my/info路由的处理函数exports.getInfo = (req, res) => { res.send('/my/info handler')}- 1
- 2
- 3
- 4
- 修改
/router/my.js文件中代码如下:
// 引入express模块const express = require('express')//创建路由对象const router = express.Router()const myHandler = require('../router_handler/my') //(*)//挂接/info路由router.get('/info', myHandler.getInfo)//(*)//向外分享路由对象module.exports = router- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
注意上述代码中(*)处的改动。
- 测试路由处理函数
如果返回的内容和我一样就没有问题了。
5.获取用户信息
- 导入
/db/index模块
const db = require('../db/index')- 1
- 编写SQL语句
const sql = 'select id,username,nickname,email,avatar from t_users where id=?'- 1
- 执行查询语句
db.query(sql, req.user.id, (err, results) => { if (err) return res.cc(err.message) if (results.length !== 1) return res.cc('获取用户信息失败') res.send({ status: 200, message: 'Success', data: results[0] })});- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
6.测试
这样就执行成功了。
更新用户信息
使用/my/info的POST请求更新用户个人信息。
1.实现步骤
- 定义路由
- 验证表单数据
- 更新用户信息
2.定义路由和处理函数
- 在
/router/my.js中新增POST路由
//更新信息router.post('/info', myHandler.setInfo)- 1
- 2
- 添加处理函数
//router_handler/my.js//设置用户信息exports.setInfo = (req, res) => { res.rend('post /my/info handler')}- 1
- 2
- 3
- 4
- 5
- 测试路由
3.参数验证
- 定义验证规则
新建/schema/my.js文件,编辑如下:
//schema/my.js//导入验证规则模块const joi = require('joi')//定义验证规则const id = joi.number().integer().min(1).max(10).required()const nickname = joi.string().required()const email = joi.string().email().required()//导出验证规则exports.update_info_schema = { body: { id, nickname, email }}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 引入验证中间件
在/router/my.js中引入express-joi中间件
// 引入验证中间件const express_joi = require('@escook/express-joi')- 1
- 2
- 引入验证规则
在/router/my.js中引入joi验证规则
// 引入验证规则const { update_info_schema } = require('../schema/my')- 1
- 2
- 在
/my/info的POST路由添加验证
//更新信息router.post('/info', express_joi(update_info_schema), myHandler.setInfo)- 1
- 2
- 验证测试
如果我们不提供id参数,就会报如下错误。
如果我们提供正确的参数,将获得如下结果: