Node.js 第四天 express路由,中间件

Express路由

路由的概念

什么是路由

广义上来讲,路由就是映射关系

image-20220429123844599

Express中的路由

在Express中,路由指的是客户端的请求和服务处理函数之间的映射关系

Express中的路由分3部分组成,分别是请求的类型 , 请求的URL地址 , 处理函数

Express路由实例

这个就是我们前面经常用的例子

//匹配GET请求,且请求URL为/
app.get('/',function(req,res){
    res.send('Hello world')
})
//匹配POST请求,且请求URL为/
app.post('/',function(req,res){
    res.send('GOT a POST request')
})

路由的匹配过程

每当一个请求到达服务器之后, 需要先经过路由的匹配 , 只有匹配成功后 , 才会调用对应的处理函数

在匹配时,按照路由的顺序进行匹配,如果请求的类型和URL同时匹配,则会执行对应的函数来处理这次的请求

就是说,我们可以根据不同的请求类型和不同的URL,定义多个app.get()app.post() , 当收到一个请求时, 按照刚才定义的顺序去匹配

image-20220429124533066

注意

  • 按照定义的先后顺序进行匹配
  • 请求类型和请求URL同时匹配成功,才会调用相应的处理函数

路由的使用

最简单的用法

也就是我们刚才说的那个示例代码

const express = require('express')
//创建web服务器
const app = express()

//挂载路由
app.get('/',(req,res)=>{res.send('hello world')})
app.post('/',(req,res)=>{res.send('别发了,我收到了')})
//启动web服务器
app.listen(80,()=>{
    console.log('app is running at http://127.0.0.1')
})

但是这种方法我们一般很少使用, 你想想 , 加入我的项目结构很复杂 , 那岂不是需要些很多的app.get()app.post() , 整个代码的体量就会很大

模块化路由

为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上 , 而是推荐将路由抽离为单位的模块 , 简单点说 , 就是我们把挂载路由的部分代码单独放到一个.js文件中

  1. 创建路由模块对应的.js文件
  2. 调用express.Router()函数创建路由对象
  3. 向路由对象上挂载具体的路由
  4. 调用module.exports向外共享这个路由对象
  5. 使用app.use()函数注册路由模块

创建路由模块

var express = require('express')
var router = express.Router()
router.get('/user',(req,res) => {
    res.send('Get User list')
})
router.post('/user',(req,res) => {
    res.send('Post a request')
})
module.exports = router

注册路由

在项目文件.js 引入路由模块

// 导入路由模块
const userRouter = require('./Router.js')
// 使用app.use() 注册路由模块 
app.use(userRouter)

这样访问http://127.0.0.1/user

为路由模块添加前缀

类似于前面所说的静态资源托管 , 路由模块也支持添加前缀的方式

//导入路由模块
const userRouter = require('./Router.js')
//调用app.use()注册路由模块 , 并添加统一的访问前缀 /api
app.use('/api',userRouter)

这样 , 当我们请求时,需要加上api前缀,http://127.0.0.1/api/user

Express中间件

中间件的概念

什么是中间件

特指业务流程的中间处理环节

中间价一般都输输入和输出, 上一级的输出作为下一级的输入

举个现实生活中的例子

image-20220429194046688

Express中间件的调用流程

当一个请求达到Express服务器之后, 可以连续调用多个中间件, 从而对这次请求进行预处理

image-20220429194223562

Express中间件的格式

Express中间件的本质就是一个function处理函数

image-20220429203824176

前面的路由函数的形参列表只包含req,res两个参数,

在中间件函数的形参列表中, 必须包含next参数

next函数的作用

next函数是多个中间件连续调用的关键 , 他表示把流转关系转交给下一个中间件或路由

next就好像是C语言中的一个指针 , 他指向下一个中间件或路由

image-20220429204051311

Express中间件初体验

定义中间件函数

可以通过如下的方式, 定义一个最简单的中间件函数

//常量mw 所指向的,就是一个中间件函数
const mw = function(req, res ,next){
    console.log('这是一个最简单的中间件函数')
    //注意, 在当前中间件的业务处理完毕后, 必须调用next()方法
    //表示把流转关系转交给下一个中间件或路由
    next();
}

全局生效的中间件

客户端发起的任何请求, 到达服务器之后 , 就会触发的中间件 ,叫做全局生效的中间件

通过调用app.use(中间件函数) , 即可定义一个全局生效的中间件函数

//常量mw 所指向的,就是一个中间件函数
const mw = function(req, res ,next){
    console.log('这是一个最简单的中间件函数')
    //注意, 在当前中间件的业务处理完毕后, 必须调用next()方法
    //表示把流转关系转交给下一个中间件或路由
    next();
}
app.use(mw)

定义全局中间件的简化形式

//全局生效的中间件的简化形式
app.use(function(req,res,next){
    console.log('这是一个中间件函数')
    next()
})

中间件的作用

多个中间件之间 , **共享同一份req和res ** , 基于这样的特性 , 我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法 , 供下游的中间件或路由进行使用

image-20220429210318783

定义多个全局中间件

当我们定义了多个全局中间件时 , 程序会按照全局中间件的顺序来依次处理

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(80,()=>{
    console.log('app is running')
})

局部生效的中间件

不使用app.use()定义的中间件 , 叫做局部生效的中间件

想要在哪个地方使用中间件函数, 直接在哪个地方调用即可

const express = require('express')
const app = express()

//定义一个中间件函数
const m1 = (req,res , next)=>{
    console.log('我是一个局部生效的中间件')
    next()
}
//我们想要这个中间件函数只在第一个路由中生效
//只需要将这个中间件函数放在路由处理函数前面的参数位置即可
app.get('/',m1,(req,res)=>{
    res.send('Home page')
})

app.get('/user',(req,res)=>{
    res.send('user page')
})
app.listen(80,()=>{
    console.log('app is running')
})

定义多个局部中间件

可以在路由中, 通过如下两种等价的方式 , 使用多个局部中间件

//以下两种写法是完全等价的
app.get('/',m1,m2,(req,res)=>{res.send('HOme page')})
app.get('/',[m1,m2],(req,res)=>{res.send('HOMe Page')})

也是按照局部中间件的顺序去调用的

了解中间件的5个使用注意事项

  • 一定要在路由之前注册中间件 , 因为整个程序是从前到后执行的 , 如果中间价在路由之后, 那么久直接响应给客户端了 , 中间件就没有用了
  • 执行完中间件的处理后, 千万别忘记调用next()函数
  • 调用完next()之后, 就不要再写多余的代码了 , 因为执行到next()的时候,就已经转入下一个中间件或者路由了, next()后面的代码就屁用没有了

中间件的分类

为了方便使用 , Express官方把常见的中间件用法 , 分成了5大类 , 分别是

  • 应用级别的中间件
  • 路由级别的中间件
  • 错误级别的中间件
  • Express 内置的中间件
  • 第三方的中间件

应用级别的中间件

通过app.use()app.get()app.post() , 绑定到app实例上的中间件 , 叫做应用级别的中间件

app.use((req,res,next)=>{
    console.log('经过第一次处理')
    next()
})
app.get('/',[m1,m2],(req,res)=>{
    res.send('Home page')
})

路由级别的中间件

绑定到express.Router()实例上的中间件 , 叫做路由级别的中间件 , 他的用法和应用级别中间件相同.

只不过,应用级别的中间件是绑定到app实例上的 , 路由级别的中间件是绑定到router实例上,

const router = express.Router()

//路由级别的中间件
router.use(function(req,res,next){
    console.log('到达路由级别中间件')
    next()
})

app.use(router)

错误级别的中间件

作用: 专门用来捕获项目中发生的异常 , 从而防止项目异常崩溃

当项目中发生错误时 , 就会直接进入到错误级别的中间件 进行处理

格式 : 错误级别的中间件处理函数 , 必须有4个形参 , 且这四个形参的顺序不能乱,分别是(err,req,res,next)

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)
})

项目发生错误后, 直接进入错误级别中间件

注意 : 错误级别中中间件 , 必须注册在所有路由之后 , 否则无效

Express内置的中间件

自express4.16.0版本之后 , Express内置了3个常用的中间件 , 极大地提高了Express项目的开发效率和体验

  • express.static 快速静态托管静态资源的内置中间件 , 例如 , HTML 文件 , 图片 ,css样式
  • express.json 解析JSON格式的请求体数据
  • express.urlencoded 解析URL-encoded格式的请求体数据

使用时只需要配置一下中间件即可

//配置全局中间件
//配置解析application/json格式数据的内置中间件
app.use(express.json())
//配置解析application/x-www-form-urlencoded格式数据的内置中间件
app.use(express.urlencoded({extended: false}))

看一个实例 , express.json的使用 , 向服务器发送一个json格式的数据

const express = require('express')
const app = express()
//配置全局中间件
// 配置解析application/json格式数据的内置中间件
//通过这个中间件, 就会将解析出来的数据挂载到req.body身上
app.use(express.json())

app.post('/user', (req, res) => {
    //在服务器 , 可以使用req.body这个属性 
    //来接收客户端发送过来的请求体数据
    //默认情况下 , 如不配置解析表单数据的中间件 , 
    //则req.body默认等于undefined
    console.log(req.body)
    res.send('ok')
})
app.listen(80, () => {
    console.log('app is running')
})

express.urlencoded的使用, 向服务器发送一个x-www-form-urlencoded格式的数据

const express = require('express')
const app = express()
//配置全局中间件

//配置解析application/x-www-form-urlencoded格式数据的内置中间件
//需要传一个配置对象 
//将解析出来的数据挂载到req.body身上
app.use(express.urlencoded({extended: false}))

app.post('/book',(req,res) =>{
    //在服务器端 , 可以通过req.body来获取json格式的表单数据和url-encoded格式的数据
    //url-encoded是一种键值对形式的数据
    console.log(req.body)
    res.send('OK')
})
app.listen(80, () => {
    console.log('app is running')
})

第三方的中间件

非 Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。

image-20220430123214310

注意: express内置的express.urlencoded中间件就是基于body-parser这个第三方中间件进一步封装出来的 , 4.16之后的版本就不需要安装上面提到的那个插件了

自定义中间件

需求描述与实现步骤

自己手动模拟一个类似于express.urlencoded这样的中间件 , 来解析POST提交到服务器的表单数据

实现步骤

  1. 定义中间件
  2. 监听 req 的 data 事件
  3. 监听 req 的 end 事件
  4. 使用 querystring 模块解析请求体数据
  5. 将解析出来的数据对象挂载为 req.body
  6. 将自定义中间件封装为模块

定义中间件

使用app.use()来配置全局中间件

app.use((req,res,next){
	//.....        
})

监听req的data事件

在中间件中国 , 需要监听req对象的data事件, 来获取客户端发送到服务器的数据

如果数据量比较大 , 无法一次性发送完毕 , 则客户端会把数据切割后 , 分批发送到服务器

所以data事件可能会触发多次 , 每一次触发data事件 , 获取到数据只是完整数据的一部分, 需要手动对接收到的数据进行拼接

    //待拼接的字符串
    let str = ''
    req.on('data',(chunk) =>{
        str += chunk;
    })

监听req的end事件

当请求体数据接收完毕之后, 会自动触发req的end 事件

因此我们可以在req的end事件中 , 拿到并处理完整的请求体数据

使用querystring模块解析请求体数据

Node.js内置了一个querystring模块 , 专门用来处理查询字符串, 通过这个模块提供的parse()函数 , 可以轻松把查询字符串, 解析成对象的格式

    req.on('end',()=>{
        //在str中存放的是完整的数
        // console.log(str)
        //把字符串解析为对象格式
        const body = qs.parse(str)
        console.log(body)
    })

整体代码

const express = require('express')
const res = require('express/lib/response')
const qs = require('querystring')
const app = express()
//这是解析表单数据的中间件
app.use((req,res,next)=>{
    //定义中间件的逻辑处理
    //待拼接的字符串
    let str = ''
    req.on('data',(chunk) =>{
        str += chunk;
    })
    req.on('end',()=>{
        //在str中存放的是完整的数
        // console.log(str)
        //把字符串解析为对象格式
        const body = qs.parse(str)
        console.log(body)
        req.body = body
        next()
    })
})
app.post('/user',(req,res)=>{
    res.send(req.body)
})
app.listen(80,()=>{
    console.log('app is running')
})

将解析出来的数据对象挂载为req.body

因为整个过程中, 中间件和路由共享同一份reqres , 所以可以在上游中间件中挂载自定义属性

red.body = body

将自定义中间件封装为模块

为了优化代码结构, 我们把自定义的中间件函数 , 封装为独立的模块, 向外共享这个函数

const qs = require('querystring')
//定义一个中间件函数
my_urlencoded = (req,res,next)=>{
    //定义中间件的逻辑处理
    //待拼接的字符串
    let str = ''
    req.on('data',(chunk) =>{
        str += chunk;
    })
    req.on('end',()=>{
        //在str中存放的是完整的数
        // console.log(str)
        //把字符串解析为对象格式
        const body = qs.parse(str)
        console.log(body)
        req.body = body
        next()
    })
}
module.exports = {
    my_urlencoded
}    

声明

此篇文章 根据黑马程序员视频教程和课件 整理而来
黑马程序员Node.js视频教程
https://www.bilibili.com/video/BV1a34y167AZ?spm_id_from=333.337.search-card.all.click

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
<h3>回答1:</h3><br/>Node.js是一种基于JavaScript语言的后端开发平台,能够运行在服务器上。ExpressNode.js的一个Web应用程序框架,它提供了许多工具和函数,使开发Web应用变得更加容易和快捷。MySQL是一种开源关系型数据库管理系统,它能够存储和管理数据。 结合这三个技术,可以开发出一个使用Node.jsExpress构建的Web应用程序,同时使用MySQL作为其数据库管理系统。这个Web应用程序可以使用Express提供的路由中间件进行开发,使用MySQL进行数据的存储和管理。开发者可以使用JavaScript语言编写后端代码,同时利用Node.js的异步编程特性,构建高性能的Web应用程序。 <h3>回答2:</h3><br/>Node.js是一个让JavaScript运行在服务器端的开源、跨平台、事件驱动的JavaScript运行环境,它拥有非阻塞I/O和事件驱动机制的优势,使得它在高并发和大数据量的情况下有着出色的表现。而Express则是一个基于Node.js平台的极简、灵活的web应用开发框架,它提供了丰富的特性和工具,可以帮助开发者快速地搭建高性能、健壮的Web应用程序。 MySQL是最流行的关系型数据库管理系统之一,它拥有完善的事务处理、并发控制、数据存储和查询功能等。与Node.jsExpress结合使用,可以为我们的Web应用提供高效的数据库支持。 基于Node.jsExpress的Web应用程序通常遵循MVC模式开发,即Model-View-Controler(模型-视图-控制器)模式。其中Model是指数据模型,View是指用户界面,Controller是指控制器,它们之间的关系如下图所示: ![MVC模式示意图](https://pic3.zhimg.com/80/v2-2266d92532f5737f62351f8185839c58_720w.jpg) 在Node.jsExpress的Web应用程序中,我们可以使用MySQL作为我们的数据库,通过MySQL的ORM(对象关系映射)工具Sequelize来实现SQL的操作。同时,我们还可以使用Node.js中的NPM(Node Package Manager)来管理我们的依赖包,例如我们可以使用body-parser来解析HTTP请求消息体,使用cookie-parser来解析cookie等。 综上所述,Node.jsExpress与MySQL可以为我们提供高效、灵活、安全的Web应用程序开发体验,让我们可以更轻松地搭建出符合需求的Web应用程序。 <h3>回答3:</h3><br/>Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,可以在服务器端运行JavaScriptExpress是一个基于Node.js的Web应用开发框架,提供了一系列的工具和功能,可以方便地开发Web应用。而MySQL是一种关系型数据库管理系统。 Node.js Express MySQL项目通常用于开发Web应用,这些应用可以访问和管理MySQL数据库中存储的数据。通过使用Express作为开发框架,可以快速构建出具有完善功能的Web应用程序。同时,通过Node.js的异步非阻塞事件驱动模型,Web应用可以更高效地处理请求和响应。 在Node.js Express MySQL项目中,需要进行以下几个主要步骤: 1. 数据库连接配置:通过配置文件或环境变量等方式,设置MySQL数据库的连接信息,包括主机地址、端口、数据库名、用户名、密码等。 2. 创建数据库模型:使用Node.js的相关模块,如mysql2、sequelize等,创建数据库模型。这些模型可以对数据库进行查询、增加、删除、修改等操作。 3. 路由控制器:使用Express提供的路由控制器实现URL命令的路由处理,对于不同的请求URL进行不同的处理。 4. 模板引擎:使用模板引擎(如Pug、Handlebars等)将服务器端生成的HTML代码与动态数据集合在一起,生成最终的Web页面。 5. 中间件:使用Express提供的中间件,如cookie-parser、body-parser、session等,来完成各种不同的任务。 Node.js Express MySQL项目可以用于开发诸如社交网络、在线商店、博客、论坛等各种类型的Web应用程序。通过使用这些工具,可以轻松地创建出高效、响应式、可靠性高的Web应用程序。同时,由于这些技术都是基于JavaScript实现的,因此开发人员可以更加专注于业务逻辑和功能的实现,而不必花费太多时间在学习新技术上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋天code

不用打赏,看看就好,谢谢

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值