express 的中间件
- 全局中间件:
- 直接在 index.js 中书写的中间件
- 使用方式: server.use(以什么开头, 函数)
- 以什么开头: 可以不写
- 函数: 你这个中间件要做的事情
- 路由级中间件
- 在路由中书写
- 使用方式: Router.use(以什么开头, 函数)
- 以什么开头: 可以不写
- 函数: 你这个中间件要做的事情
- 请求级中间件
- 在请求的处理中书写, 需要在路由处理函数之前书写
- 错误处理中间件(本质上就是全局中间件)
- 必须放在 监听端口号前一位,中间不能有其他代码
配置全局中间件
新建一个index.txt文件,用来记录请求
修改服务器端文件如下:
// 0.导入第三方模块
const express = require('express')
const Router = require('./router')
const bodyParser = require('body-parser')
const fs = require('fs') //node给我们提供的内置模块,导入直接使用即可
// 1.开启服务
const server = express()
// 1.1 解析post参数
// 解析 application/x-www-form-urlencoded (普通字符串)
server.use(bodyParser.urlencoded({ extended: false }))
// 解析 application/json (json字符串)
server.use(bodyParser.json())
// 1.1.1 配置全局中间件
server.use((req, res, next) => {
/**
* 需求:在每一次请求这个服务器的时候,记录一下
*
* 解决: 利用node.js 给我们提供的内置模块 fs 来操作
*
* 语法: fs.appendFile('修改的文件路径', `追加到这个文件内的内容,追加完毕后的回调函数(不执行内容也要写一个空函数)`)
* */
fs.appendFile('./index.txt', `${new Date()} ----- ${req.url}\n`, () => {})
/**
* 中间会有第三个参数,next,他是一个函数,如果不调用,那么你的所有请求,都会卡在这个函数中
* */
next()
})
// 1.2开启静态服务
server.use('/static', express.static('./client'))
// 1.2配置请求路由
server.use('/api', Router)
// 2.监听一个端口号
server.listen(8080, () => {
console.log('服务器开启成功')
})
配置路由级中间件
修改router文件夹下的users.js文件:
// 导入第三方模块
const express = require('express')
const { postUsersInfo, postUsersSetName } = require('../controller/users')
/**
* 在当前服务器中,只要是users开头的接口,全都需要登陆过
* 换句话说,就是请求/users 不管后续的接口是什么,全都需要携带token
* 所以我们为了减少代码量,好维护代码.我们就需要使用到 路由级别的中间件
* */
// 创建一张路由分表
const UsersRouter = express.Router()
// 挂在路由级别的 中间件
UsersRouter.use((req, res, next) => {
// console.log('当前服务器接收到一条请求,需要验证token');
// 1. 验证token,如果token存在,那么继续向下进行,如果不存在,直接拦截,并且反馈给前端一个信息
console.log(req.headers.authorization) //假设我们的token就是123456
if(!req.headers.authorization) {
res.send({
code: 0,
msg: '当前接口需要传递token'
})
return
}
if(req.headers.authorization !== '123456') {
res.send({
code: 0,
msg: '当前token 过期或伪造'
})
return
}
next()
})
// 想分表上挂载一些请求处理
UsersRouter.post('/info', postUsersInfo)
UsersRouter.post('/setName', postUsersSetName)
// 导出当前分表
module.exports = UsersRouter
修改client文件夹下js文件夹下的index.js文件
function myAjax2() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('post', '/users/info')
xhr.open('post', '/api/users/info')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
//token的值,123456是满足token的值,会请求成功
xhr.setRequestHeader('authorization', '123456')
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send('id=20040216')
}
myAjax2()
配置请求级中间件
- 请求中间件, 一般是用来验证参数的
新建一个middleware文件夹,在其下边新建一个goods.js,该文件专门存储 goods请求相关的中间件函数
exports._getGoodsList = (req, res, next) => {
// 验证参数是否符合要求,如果符合那么继续向下,不符合直接拦截
const {current, pageSize} = req.query;
console.log(current, pageSize)
// 1. 非空校验
if(!current || !pageSize) {
res.send({
code: 0,
msg: '参数数量不对请检查'
})
return
}
/**
* 2. 格式校验
* isNaN: 会将传递进去的参数,转换为数字类型
* 并且会验证是否为一个NaN
* '123' -> 123
* 'abc' -> NaN
* */
if(isNaN(current) || isNaN(pageSize)) {
res.send({
code: 0,
msg: '参数格式不对'
})
return
}
next()
}
修改router文件夹下的goods.js文件:
// 导入第三方模块
const express = require('express')
const { getGoodsList, getGoodsInfo } = require('../controller/goods');
const { _getGoodsList } = require('../middleware/goods');
// 创建一张路由分表
const GoodsRouter = express.Router()
// 想分表上挂载一些请求处理
//_getGoodsList这个就是引入middleware文件中的变量
GoodsRouter.get('/list', _getGoodsList, getGoodsList)
GoodsRouter.get('/info', getGoodsInfo)
// GoodsRouter.get('/info', testUserName, getGoodsInfo)
// 导出当前分表
module.exports = GoodsRouter
配置错误处理中间件
修改服务器端文件如下:
// 0.导入第三方模块
const express = require('express')
const Router = require('./router')
const bodyParser = require('body-parser')
const fs = require('fs') //node给我们提供的内置模块,导入直接使用即可
// 1.开启服务
const server = express()
// 1.1 解析post参数
// 解析 application/x-www-form-urlencoded (普通字符串)
server.use(bodyParser.urlencoded({ extended: false }))
// 解析 application/json (json字符串)
server.use(bodyParser.json())
// 1.1.1 配置全局中间件
server.use((req, res, next) => {
fs.appendFile('./index.txt', `${new Date()} ----- ${req.url}\n`, () => {})
next()
})
// 1.2开启静态服务
server.use('/static', express.static('./client'))
// 1.3配置请求路由
server.use('/api', Router)
// 全局错误处理中间件
server.use((error, req, res, next) => {
// console.log('全局处理中间件')
/**
* 约定: (自己和自己约定)
* error === 2
* 参数数量不够
* error === 3
* 参数格式不对
* error === 4
* token 没有传递
* error === 5
* token 伪造/过期
* */
console.log(error)
if(error === 2) {
res.send({
code: 0,
msg: '参数数量不够'
})
}else if(error === 3) {
res.send({
code: 0,
msg: '参数格式不对'
})
}else if(error === 4) {
res.send({
code: 0,
msg: 'token 没有传递'
})
}else if(error === 5) {
res.send({
code: 0,
msg: 'token 伪造/过期'
})
}
})
// 2.监听一个端口号
server.listen(8080, () => {
console.log('服务器开启成功')
})
修改middleware文件夹下的goods.js文件:
- goods.js文件:
// 该文件专门存储 goods请求相关的中间件函数
exports._getGoodsList = (req, res, next) => {
// 验证参数是否符合要求,如果符合那么继续向下,不符合直接拦截
const {current, pageSize} = req.query;
console.log(current, pageSize)
// 1. 非空校验
if(!current || !pageSize) {
// res.send({
// code: 0,
// msg: '参数数量不对请检查'
// })
// return
return next(2)
}
/**
* 2. 格式校验
* isNaN: 会将传递进去的参数,转换为数字类型
* 并且会验证是否为一个NaN
* '123' -> 123
* 'abc' -> NaN
* */
if(isNaN(current) || isNaN(pageSize)) {
// res.send({
// code: 0,
// msg: '参数格式不对'
// })
// return
return next(3)
}
next()
}
exports._getGoodsInfo = (req, res, next) => {
// 验证参数是否符合要求,如果符合那么继续向下,不符合直接拦截
const {goodsId} = req.query;
console.log(goodsId)
// 1. 非空校验
if(!goodsId) {
// res.send({
// code: 0,
// msg: '参数数量不对请检查'
// })
// return
return next(2)
}
/**
* 2. 格式校验
* isNaN: 会将传递进去的参数,转换为数字类型
* 并且会验证是否为一个NaN
* '123' -> 123
* 'abc' -> NaN
* */
if(isNaN(goodsId)) {
// res.send({
// code: 0,
// msg: '参数格式不对'
// })
// return
return next(3)
}
next()
}
修改router文件夹下的goods.js文件和users.js文件:
- goods.js文件:
// 导入第三方模块
const express = require('express')
const { getGoodsList, getGoodsInfo } = require('../controller/goods');
const { _getGoodsList, _getGoodsInfo } = require('../middleware/goods');
// 创建一张路由分表
const GoodsRouter = express.Router()
// 想分表上挂载一些请求处理
GoodsRouter.get('/list', _getGoodsList, getGoodsList)
GoodsRouter.get('/info', _getGoodsInfo, getGoodsInfo)
// 导出当前分表
module.exports = GoodsRouter
- users.js文件:
// 导入第三方模块
const express = require('express')
const { postUsersInfo, postUsersSetName } = require('../controller/users')
/**
* 在当前服务器中,只要是users开头的接口,全都需要登陆过
*
* 换句话说,就是请求/users 不管后续的接口是什么,全都需要携带token
*
* 所以我们为了减少代码量,好维护代码.我们就需要使用到 路由级别的中间件
* */
// 创建一张路由分表
const UsersRouter = express.Router()
// 挂在路由级别的 中间件
UsersRouter.use((req, res, next) => {
// 1. 验证token,如果token存在,那么继续向下进行,如果不存在,直接拦截,并且反馈给前端一个信息
console.log(req.headers.authorization) //假设我们的token就是123456
if(!req.headers.authorization) {
/**
* next如果直接调用,是进入到下一个中间件
* 但是在调用的时候,还可以传递一个参数
* 如果这个参数传递了值,会跳转到全局错误处理中间件
* 然后全局错误处理中间件的第一个形参,就是我们调用的时候穿的参数
* */
return next(4)
}
if(req.headers.authorization !== '123456') {
return next(5)
}
next()
})
// 想分表上挂载一些请求处理
UsersRouter.post('/info', postUsersInfo)
UsersRouter.post('/setName', postUsersSetName)
// 导出当前分表
module.exports = UsersRouter
- 注: 在终端输入nodemon 文件名,打开浏览器输入http://localhost:8080/static/view/index.html 运行
- 运行结果:
动态路由
在router文件夹下新建一个cart.js文件, 购物车的接口,将来也是需要登录后才能访问的接口 配置分表cart.js文件的代码:
// 购物车的接口,将来也是需要登录后才能访问的接口
// 导入第三方包
const express = require('express')
// 创建路由分表
const CartRouter = express.Router()
/**
* 我们目前一直使用的路由, 传参方式, 就是这样
* 但是有一天, 有一个人, 觉得这样写太丑了, 然后研究出来一个叫做 动态路由的东西
*/
// 向路由总表上添加路由分表
// 动态路由写法
CartRouter.get('/list/:current', (req, res) => {
/**
* 如果是动态路由的写法, 参数就不会放在 req.query
* 而是放在 req.params (post 与 get 都一样)
*/
res.send({
code: 1,
msg: '需求成功',
tips: `您请求的列表页为第 ${req.params.current}`
})
})
CartRouter.post('/add/:name', (req, res) => {
res.send({
code: 1,
msg: '需求成功',
tips: `您请求的列表页为第 ${req.params.name}`
})
})
// 原本写法
// CartRouter.get('/list', (req, res) => {
// res.send({
// code: 1,
// msg: '需求成功',
// tips: `您请求的列表页为第 ${req.query.current}`
// })
// })
// CartRouter.post('/add', (req, res) => {
// res.send({
// code: 1,
// msg: '需求成功',
// tips: `您请求的列表页为第 ${req.body.name}`
// })
// })
module.exports = CartRouter
将分表cart.js文件引入总表index.js文件
// 导入第三方模块
const express = require('express');
const CartRouter = require('./cart');
const GoodsRouter = require('./goods');
const UsersRouter = require('./users');
// 创建一个总表
const Router = express.Router();
// 向路由总表上挂载路由分表
Router.use('/goods', GoodsRouter);
Router.use('/users', UsersRouter);
Router.use('/cart', CartRouter)
// 导出路由总表
module.exports = Router;
配置client文件夹下js文件夹下的index.js文件:加入了myAjax5和myAjax6函数
// 前端的代码, 发送一个请求
function myAjax1() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('get', '/goods/list')
xhr.open('get', '/api/goods/list?current=1&pageSize=12')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
xhr.send()
}
myAjax1()
function myAjax2() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('post', '/users/info')
xhr.open('post', '/api/users/info')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
xhr.setRequestHeader('authorization', '123456')
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send('id=20040216')
}
myAjax2()
function myAjax3() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('get', '/goods/list')
xhr.open('get', '/api/goods/info?goodsId=10086')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
xhr.send()
}
myAjax3()
function myAjax4() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('post', '/users/info')
xhr.open('post', '/api/users/setName')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
xhr.setRequestHeader('authorization', '123456')
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send('id=20040216')
}
myAjax4()
function myAjax5() {
// console.log('向服务端发起一个请求')
const xhr = new XMLHttpRequest()
// xhr.open('get', '/api/cart/list?current=10086')
xhr.open('get', '/api/cart/list/10086')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
xhr.send()
}
myAjax5()
function myAjax6() {
const xhr = new XMLHttpRequest()
// xhr.open('post', '/api/cart/add')
xhr.open('post', '/api/cart/add/老北京卤煮')
xhr.onload = function() {
console.log(JSON.parse(xhr.responseText))
}
// xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// xhr.send('name=老北京卤煮')
xhr.send()
}
myAjax6()
- 注: 在终端输入nodemon 文件名,打开浏览器输入http://localhost:8080/static/view/index.html 运行
- 运行结果: