1、路由就是映射关系
2、根据不同的用户URL请求,返回不同的内容
3、本质:URL请求地址与服务器资源之间的对应关系
在
Express
中,路由指的是客户端的请求与服务器处理函数之间的映射关系Express 中的路由分 3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数
3.Express 中的路由的例子
每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数
在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则
Express
会将这次请求,转交给对应的 function 函数进行处理
3、路由匹配的注意点
按照定义的先后顺序进行匹配
请求类型和请求的URL同时匹配成功,才会调用对应的处理函数
在
Express
中使用路由最简单的方式,就是把路由挂载到app
上
案例代码
const express = require('express') // 创建 web 服务器,命名为 app const app = express() // 挂载路由 app.get('/', (req, res) => { res.send('Hello, World') }) app.post('/', (req, res) => { res.send('Hello, Tom') }) app.listen(3000, () => { console.log('running……') })
为了方便对路由进行模块化的管理,
Express
不建议将路由直接挂载到app
上,而是推荐将路由抽离为单独的模块,将路由抽离为单独模块的步骤如下
创建路由模块对应的
.js
文件调用
express.Router()
函数创建路由对象向路由对象上挂载具体的路由
使用
module.exports
向外共享路由对象使用
app.use()
函数注册路由模块
案例代码:
// 1. 导入 express const express = require('express') // 2. 创建路由对象 const router = express.Router() // 3. 挂载获取用户列表的路由 router.get('/user/list', (req, res) => { res.send('用户列表') }) // 4. 挂载添加用户列表的路由 router.post('/user/add', (req, res) => { res.send('添加用户') }) // 5. 向外导出路由对象 module.exports = router
导入路由模块
使用
app.use()
注册路由模块
案例代码:
const express = require('express') const app = express() // 导入路由模块 const userRouter = require('./002-router') // 使用 app.use() 注册路由模块 app.use(userRouter) app.listen(3000, () => { console.log('running……') })
类似于托管静态资源写法,为静态资源统一挂载访问前缀一样
注意,添加了路由前缀后,访问的路由的时候,也应该加上前缀
案例代码:
const express = require('express') const app = express() // 导入路由模块 const userRouter = require('./002-router') // 使用 app.use() 注册路由模块 // 给路由模块添加统一得到访问前缀 /api app.use('/api', userRouter) app.listen(3000, () => { console.log('running……') })
什么是中间件
所谓的中间件(
Middleware
),特指业务流程的中间处理环节现实生活中的例子
在处理污水的时候,一般都要经过三个处理环节,从而保证处理过后的废水,达到排放标准
处理污水的这三个中间处理环节,就可以叫做中间件
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
Express的中间件,本质上就是一个function处理函数,Express中间件的格式如下:
注意:中间件函数的形参列表中,必须包括next函数。而路由处理函数中只包含req和res
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
通过一下方式,定义一个最简单的中间件函数
const express = require('express') const app = express() // 定义一个最简单的中间件函数 const mw = function(req, res, next){ console.log('这是最简单的中间件函数') // 把流转关系,转交给下一个中间件或者路由 next() } app.listen(80, () => { console.log('running……') })
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。通过调用app.use(中间件函数),即可定义一个全局生效的中间件:
const express = require('express') const app = express() // 定义一个最简单的中间件函数 const kw = (req, res, next) => { console.log('这是最简单的中间件函数') // 把流转关系,转交给下一个中间件或者路由 next() } // 全局生效的中间件(处理所有的请求) app.use(kw) app.get('/', (req, res) => { console.log('调用了 / 这个路由') res.send('Home page') }) app.get('/user', (req, res) => { console.log('调用了 /user 这个路由') res.send('User page') }) app.listen(3000, () => { console.log('running……') })
直接将我们的全局中间件挂载到app.use()上面
const express = require('express') const app = express() // 定义全局中间件的简化形式 app.use((req, res, next) => { console.log('定义全局中间件的简化形式') next() }) app.get('/', (req, res) => { console.log('调用了 / 这个路由') res.send('Home page') }) app.get('/user', (req, res) => { console.log('调用了 /user 这个路由') res.send('User page') }) app.listen(3000, () => { console.log('running……') })
在多个中间件之间,他们是共享同一份的res和req对象的(前提必须是中间件调用了next)
通过这种特性,我们可以直接在中间件函数上进行我们想要影响到下方路由的操作
可以使用app.use()连续的监听定义多个全局中间件,客户端向服务器发起请求时。服务器会根据中间件的定义先前在后依次执行
const express = require('express') const app = express() // 第一个全局中间件 app.use((req, res, next) => { console.log('调用了第一个全局的中间件') next() }) // 第二个全局中间件 app.use((req, res, next) => { console.log('调用了第二个全局的中间件') next() }) // 定义路由 // 请求这两个路由,会依次触发上述两个全局中间件 app.get('/user', (req, res) => { res.send('User Page') }) app.listen(3000, () => { console.log('running……') })
不使用app.use监听的中间件,而是直接写在路由路径参数之后的,叫做局部生效的中间件
const express = require('express') const app = express() // 定义中间件函数 mv1 const mv1 = (req, res, next) => { console.log('这是中间件函数') next() } // mv1 这个中间件只在 "当前路由中生效",这种用法属于 "局部生效的中间件" app.get('/', mv1, (req, res) => { res.send('Home Page') }) app.get('/user', (req, res) => { res.send('User Page') }) app.listen(3000, () => { console.log('running……') })
1、一定要在路由之前注册中间件
2、客户端发送过来的请求,可以连续调用多个中间件进行处理
3、执行完中间件的业务代码之后,不要忘记调用next()函数
4、为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
5、连续调用多个中间件时,多个中间件之间,共享req和res对象
Express官方把常见的中间件分成了五大类:
~应用级别的中间件
~路由级别的中间件
~错误级别的中间件
~Express内置的中间件
~第三方的中间件
通过app.use()或app.get()&post()绑定到app实例上的中间件,叫做应用级别的中间件
绑定到express.Router()实例上的中间件,叫做路由级别的中间件
用法和应用级别的中间件没有任何的区别,只不过,应用级别中间件时绑定到app实例上,路由级别的中间件绑定到router实例上
错误级别的中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
格式:错误级别的中间件的function处理函数中,必须有4个形参。形参分别是(err,req,res,next)
注意:错误级别的中间件,必须注册在所有路由之后
const express = require('express') const app = express() // 1. 路由 app.get('/', (req, res) => { // 1.1 抛出一个自定义的错误 throw new Error('服务器内部发生了错误') res.send('Home Page.') }) // 2. 错误级别的中间件 // 注意:错误级别的中间件,必须注册在所有路由之后 app.use((err, req, res, next) => { // 2.1 在服务器打印错误消息 console.log('发生了错误:' + err.message) // 2.2 向客户端响应错误相关的内容 res.send(err.message) }) app.listen(3000, () => { console.log('running……') })
自Express4.16.0版本开始,Express内置了三个常用的中间件,极大的提高了Express项目开发效率和体验
1、express.static快速托管静态资源的内置中间件,例如:HTMl文件、图片、cssu样式等(注意整个方法适用于express任何的版本,就是没有版本兼容性的问题)
2、exprss.json解析JSON格式的请求体数据(有兼容性,仅在4.16.0以上的版本中可以使用)
3、express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0以上的版本可以使用)
express.json()中间件,解析表单中的JSON格式的数据
const express = require('express') const app = express() // 注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置 // 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据 app.use(express.json()) app.post('/user', (req, res) => { // 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据 // 默认情况下,如果不配置解析表单数据中间件,则 req.body 默认等于 undefined console.log(req.body) res.send('ok') }) app.listen(3000, () => { console.log('running……') })
express.urlencoded解析URL-encoded格式的请求体数据
const express = require('express') const app = express() // 通过 express.urlencoded() 这个中间件,来解析表单中的 url-encoded 格式的数据 app.use(express.urlencoded({ extended: false })) app.post('/book', (req, res) => { console.log(req.body) res.send(req.body) }) app.listen(3000, () => { console.log('running……') })
非Express官方内置,而是由第三方开发出来的中间件,叫做第三方中间件。