✅ 作者简介:一名普通本科大三的学生,致力于提高前端开发能力
✨ 个人主页:前端小白在前进的主页
🔥 系列专栏 : node.js学习专栏
⭐️ 个人社区 : 个人交流社区
🍀 学习格言: ☀️ 打不倒你的会使你更强!☀️
🔥前言
国庆期间,也不能停止学习!上一篇文章讲解了express的入门,本节开始我们将进入到核心阶段的学习,核心阶段包含了路由、中间件、编写接口三大块内容,本篇文章将从路由和中间件讲起,详细讲解路由、中间件的定义和应用。快快看过来吧😛😛
📃目录
- 初识路由
- 路由的概念
- Express中的路由
- Express中路由实例
- 路由的匹配过程
- 路由实操
- 简单使用
- 模块化路由
- 初识中间件
- 中间件定义(与生活结合)
- 中间件调用过程
- Express中间件格式
- next()的作用
- Express中间件实际体验
- 中间件的作用
- 局部生效的中间件
- 中间件的使用注意事项
- 中间件的分类
- 自定义中间件
- 中间件实际使用场景示例
- 小结
初识路由
路由的概念
广义上来讲,路由就是映射关系
。nodejs中的路由其实就是url地址
和响应函数
之间的映射关系
,一个url地址响应一个html页面
。就是将一个路径匹配关系的业务提取到一个单独的js文件当中。
说了这么多,肯定有小伙伴们还是不理解,咱们就拿生活中的例子开刀:在我们与10086
通话的时候,它的人工机器人总会提醒我们如果你想办理xxx业务,请输入按键x
,这样的关系不就是映射关系
吗?
在这里,路由是按键
与服务
之间的映射关系
。
Express中的路由
在 Express
中,路由指的是客户端的请求
与服务器处理函数
之间的映射关系
。
Express 中的路由分三部分组成
,分别是请求的类型
、请求的 URL 地址
、处理函数
,格式如下:
app.METHOD(PATH,HANDLER)
Express中路由实例
//匹配get请求,并且请求的url地址为`/`
app.get('/',(req,res)=>{
res.send('hello world')
})
//匹配post请求,并且请求的url地址为`/login`
app.post('/login',(req,res)=>{
res.send('Post Request')
})
路由的匹配过程
在上面说了匹配
这个词。这个词到底是啥意思呢?每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数
。
在匹配时,会按照路由的顺序进行匹配
,如果请求类型
和请求的 URL
同时匹配成功,则 Express 会将这次请求,转交给对应的 function 函数
进行处理。
匹配注意事项:
- 按照定义的
先后顺序
进行匹配请求类型
和请求的url
同时匹配成功,才会调用对应的处理函数
路由实操
简单使用
//引入express模块
const express = require('express')
//创建web服务器,取名为app,实质就是实例化
const app = express()
//挂载路由
app.get('/',(req,res)=>{
res.send('hello world')
})
app.post('/',(req,res)=>{
res.send('Post Request')
})
//监听服务器,启动web服务器
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
模块化路由
为了方便对路由进行模块化
的管理,Express 不建议将路由直接挂载到 app 上
,而是推荐将路由抽离为单独的模块
。将路由抽离为单独模块的步骤如下:
- 创建路由模块对应的
.js 文件
- 调用
express.Router()
函数创建路由对象 - 向路由对象上挂载具体的路由
- 使用
module.exports
向外共享路由对象 - 使用
app.use()
函数注册路由模块
具体示例:
-
创建单独的路由模块
const express = require('express') //创建路由对象 const router = express.Router() //获取用户列表的路由 router.get('/user/list',function(req,res){ res.send('Get user list') }) //添加用户的路由 router.post('/user/add',function(req,res){ res.send('Add new user') }) //向外导出路由对象 module.exports = router
-
注册路由模块
const express = require('express') const app = express() //1.导入路由模块 const router = require('./router') //注册路由模块,并添加统一的访问前缀 /api app.use('/api',router) //app.use()作用是全局注册中间件 app.listen(80,()=>{ console.log('http://127.0.0.1'); })
初识中间件
中间件定义(与生活结合)
中间件(Middleware)是一种功能的封装方式
,主要是指封装所有http请求细节处理的方法
;http的请求通常包含了许多的内容,因此可以利用中间件来简化及隔离这些基础设施
与业务逻辑
之间的细节。也可以去总结一句话,中间件就是:特指业务流程的中间处理环节
。
黑马哥举了一个生活的例子帮助我们更好的知道什么是中间件:污水处理的中间环节
,在处理污水的时候,一般都要经过三个处理环节
,从而保证处理过后的废水,达到排放标准。
处理污水的这三个中间处理环节,就可以叫做中间件
。
中间件调用过程
当一个请求到达 Express 的服务器之后,可以连续调用多个中间件
,从而对这次请求进行预处理
。
Express中间件格式
Express 的中间件,本质上就是一个 function 处理函数
,Express 中间件的格式如下:
注意:中间件函数的形参列表中,
必须包含 next 参数
。而路由处理函数中只包含 req 和 res
。
next()的作用
next 函数是实现多个中间件连续调用
的关键,它表示把流转关系转交给下一个中间件或路由
。
Express中间件实际体验
首先需要知道什么是全局生效的中间件:客户端发起的任何请求,到达服务器之后,都会触发的中间件
,叫做全局生效的中间件。
整体代码如下:
const express = require('express')
const app = express()
// const mw = function(req,res,next) {
// console.log('这是最简单的中间件函数');
// //把流转关系,转交给下一个中间件或路由
// next()
// }
// //将mw注册为全局生效的中间件
// app.use(mw)
//这是定义全局中间件的简化方式
app.use((req,res,next)=> {
const time = Date.now()
console.log('调用了第一个全局中间件');
req.startTime = time
next()
})
//定义第二个全局中间件
app.use((req,res,next)=>{
console.log('调用了第二个全局中间件');
next()
})
app.get('/',(req,res)=>{
console.log('调用了 / 这个路由');
res.send('home page' + req.startTime)
})
app.post('/user',(req,res)=>{
console.log('调用了 /user 这个路由');
res.send('User page' + req.startTime)
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
中间件的作用
多个中间件之间,共享同一份 req 和 res
。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法
,供下游的中间件或路由进行使用。
局部生效的中间件
不使用 app.use() 定义
的中间件,叫做局部生效的中间件。
示例代码如下:
const express = require('express')
const app = express()
//定义中间件函数
const mw1 = (req,res,next)=>{
console.log('这是中间件函数1');
next()
}
//定义中间件函数
const mw2 = (req,res,next)=>{
console.log('这是中间件函数2');
next()
}
//定义路由
//使用局部中间件第一种方法
app.get('/',mw1,mw2,(req,res)=>{
res.send('home page')
})
//使用局部中间件第二种方法
app.get('/user',[mw1,mw2],(req,res)=>{
res.send('hello user')
})
app.listen(80,()=>{
console.log('http://127.0.0.1');
})
中间件的使用注意事项
- 一定要在
路由之前
注册中间件 - 客户端发送过来的请求,
可以连续调用多个
中间件进行处理 - 执行完中间件的业务代码之后,
不要忘记调用 next() 函数
- 为了
防止代码逻辑混乱
,调用 next() 函数后不要再写额外的代码 - 连续调用多个中间件时,多个中间件之间,
共享
req 和 res 对象
中间件的分类
为了方便大家理解和记忆中间件的使用,Express 官方把常见的中间件用法,分成了 5 大类,分别是:
-
应用级别
的中间件
通过app.use() 或 app.get() 或 app.post()
,绑定到 app 实例上的中间件,叫做应用级别的中间件.这一种中间件就是上面我们代码写法。 -
路由级别
的中间件
绑定到express.Router()
实例上的中间件,叫做路由级别的中间件
。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到 app 实例上,路由级别中间件绑定到 router 实例上
. -
错误级别
的中间件
错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
。
格式:错误级别中间件的 function 处理函数中,必须有4 个形参
,形参顺序从前到后,分别是(err, req, res, next)
。代码示例:
const express = require('express') const app = express() //定义路由 app.get('/',(req,res)=>{ throw new Error('服务器内部发生了错误!') res.send('home page') }) //定义错误级别的中间件,捕获整个项目的异常情况,从而防止程序的崩溃 app.use((err,req,res,next)=>{ console.log('发生了错误!' + err.message); res.send('Error:' + err.message) }) app.listen(80,()=>{ console.log('http://127.0.0.1'); })
注意:错误级别的中间件,
必须注册在所有路由之后
! -
Express 内置
的中间件
自 Express 4.16.0 版本开始,Express 内置了 3 个常用的中间件,极大的提高了 Express 项目的开发效率和体验:
express.static
快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
express.json
解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
express.urlencoded
解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)//配置解析application/json 格式数据的内置中间件 app.use(express.json()) //配置解析 application/x-www-form-urlencoded 格式数据的内置中间件 app.use(express.urlencoded({extended:false}))
-
第三方
的中间件
非 Express 官方内置的,而是由第三方开发出来的中间件
,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
例如:在 express@4.16.0 之前的版本中,经常使用body-parser
这个第三方中间件,来解析请求体数据。使用步骤如下:- 运行
npm install body-parser
安装中间件 - 使用
require 导入
中间件 - 调用
app.use()
注册并使用中间件
注意:Express 内置的
express.urlencoded
中间件,就是基于body-parser
这个第三方中间件进一步封装
出来的。 - 运行
自定义中间件
自己手动模拟一个类似于 express.urlencoded
这样的中间件,来解析 POST 提交到服务器的表单数据
。
-
封装一个中间件处理函数(这个js文件名为:
custom-body-paser.js
)const qs = require('querystring') const bodyPaser = (req,res,next)=>{ let str = '' //专门用来存储客户端发过来的数据 // node.js用req.on(data)接收客户端的数据; req.on('data',(chunk)=>{ str += chunk }) req.on('end',()=>{ console.log(str); const body = qs.parse(str) req.body = body next() }) } module.exports = bodyPaser
-
模块调用
const express = require('express') const app = express() const customBodyPaser = require('./custom-body-paser') //解析表单数据的中间件 app.use(customBodyPaser) app.post('/user',(req,res)=>{ res.send(req.body) }) app.listen(80,()=>{ console.log('http://127.0.0.1'); })
中间件实际使用场景示例
讲解了中间件的知识,大家可能还是看的一脸懵逼,不知道中间件在开发中的具体作用能干啥,如果你学过了vue
,其实你很容易就明白中间件其实就是拦截器,跟路由守卫作用一样
,在实际开发中有个重要的环节,如果用户没有登录的话,那么该用户就不能访问一些页面,并且也不会获取到一些信息,比如:如果我知道个人中心的url地址,但是我没有登录,我却可以去进入我的个人中心页面,这不是扯淡吗?
,中间件就可以很好的解决这个问题。
具体小demo如下:
const loginCheck = (req, res, next) => {
if (某个登录成功的条件) {
next(); // 登录成功执行next
} else {
res.json({
err: -1,
msg: '登录失败'
})
res.redirect('/adminlogin'); // 将用户重定向到登录页面
}
}
// 若在登录状态下,loginCheck会执行next函数,从而执行第二个中间件,获取博客列表。
app.get('/api/blog/list', loginCheck, (req, res, next) => {
获得博客列表
})
小结
Express框架中路由和中间件都是必须用的,好多人在中间件的理解上总是差点意思,不能够灵活的运用中间件,你的项目将会出现大大小小的问题,因此,中间件的学习必须是要吃透的,如果你想自己结合vue+node
写一个整合性项目,中间件的使用是必不可少的!继续加油吧,少年!😀😀
👑书写不易,希望大家能够给予三连支持,期待我更好的文章哟👑