【node进阶】深度解析Express框架--路由、中间件

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
性能测试 PTS,5000VUM额度
简介: 【node进阶】深度解析Express框架--路由、中间件🔥前言国庆期间,也不能停止学习!上一篇文章讲解了express的入门,本节开始我们将进入到核心阶段的学习,核心阶段包含了路由、中间件、编写接口三大块内容,本篇文章将从路由和中间件讲起,详细讲解路由、中间件的定义和应用。快快看过来吧😛😛

16c96b3d55074655a456884563b8e035.png


初识路由


路由的概念


广义上来讲,路由就是映射关系。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 函数进行处理。


0.png


匹配注意事项:


  1. 按照定义的先后顺序进行匹配
  2. 请求类型和请求的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 上,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:


  1. 创建路由模块对应的 .js 文件
  2. 调用 express.Router() 函数创建路由对象
  3. 向路由对象上挂载具体的路由
  4. 使用 module.exports 向外共享路由对象
  5. 使用 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的请求通常包含了许多的内容,因此可以利用中间件来简化及隔离这些基础设施与业务逻辑之间的细节。也可以去总结一句话,中间件就是:特指业务流程的中间处理环节。


黑马哥举了一个生活的例子帮助我们更好的知道什么是中间件:污水处理的中间环节,在处理污水的时候,一般都要经过三个处理环节,从而保证处理过后的废水,达到排放标准。

1.png


处理污水的这三个中间处理环节,就可以叫做中间件。


中间件调用过程


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


2.png

Express中间件格式


Express 的中间件,本质上就是一个 function 处理函数,Express 中间件的格式如下:


3.png


注意:中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含 req 和 res。


next()的作用

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


4.png


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 对象添加自定义的属性或方法,供下游的中间件或路由进行使用。


5.png


局部生效的中间件


不使用 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');
})


中间件的使用注意事项


  1. 一定要在路由之前注册中间件
  2. 客户端发送过来的请求,可以连续调用多个中间件进行处理
  3. 执行完中间件的业务代码之后,不要忘记调用 next() 函数
  4. 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
  5. 连续调用多个中间件时,多个中间件之间,共享 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 这个第三方中间件,来解析请求体数据。使用步骤如下:


  1. 运行 npm install body-parser 安装中间件
  2. 使用 require 导入中间件
  3. 调用 app.use() 注册并使用中间件


注意:Express 内置的 express.urlencoded 中间件,就是基于 body-parser 这个第三方中间件进一步封装出来的。


自定义中间件


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


  1. 封装一个中间件处理函数(这个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


2.模块调用




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写一个整合性项目,中间件的使用是必不可少的!继续加油吧,少年!😀😀


相关文章
|
3月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
50 3
|
3月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
187 3
|
14天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2月前
|
负载均衡 网络协议 定位技术
在数字化时代,利用DNS实现地理位置路由成为提升用户体验的有效策略
在数字化时代,利用DNS实现地理位置路由成为提升用户体验的有效策略。通过解析用户请求的来源IP地址,DNS服务器可判断其地理位置,并返回最近或最合适的服务器IP,从而优化网络路由,减少延迟,提高访问速度。示例代码展示了如何基于IP地址判断地理位置并分配相应服务器IP,实际应用中需结合专业地理数据库和动态调整机制,以应对复杂网络环境带来的挑战。
39 6
|
2月前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
3月前
|
存储 JavaScript 前端开发
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
314 2
|
3月前
|
消息中间件 中间件 数据库
NServiceBus:打造企业级服务总线的利器——深度解析这一面向消息中间件如何革新分布式应用开发与提升系统可靠性
【10月更文挑战第9天】NServiceBus 是一个面向消息的中间件,专为构建分布式应用程序设计,特别适用于企业级服务总线(ESB)。它通过消息队列实现服务间的解耦,提高系统的可扩展性和容错性。在 .NET 生态中,NServiceBus 提供了强大的功能,支持多种传输方式如 RabbitMQ 和 Azure Service Bus。通过异步消息传递模式,各组件可以独立运作,即使某部分出现故障也不会影响整体系统。 示例代码展示了如何使用 NServiceBus 发送和接收消息,简化了系统的设计和维护。
75 3
|
2月前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
37 0
|
3月前
|
人工智能 缓存 Java
深入解析Spring AI框架:在Java应用中实现智能化交互的关键
【10月更文挑战第12天】Spring AI 是 Spring 框架家族的新成员,旨在满足 Java 应用程序对人工智能集成的需求。它支持自然语言处理、图像识别等多种 AI 技术,并提供与云服务(如 OpenAI、Azure Cognitive Services)及本地模型的无缝集成。通过简单的配置和编码,开发者可轻松实现 AI 功能,同时应对模型切换、数据安全及性能优化等挑战。
259 3
|
3月前
|
分布式计算 Java 应用服务中间件
NettyIO框架的深度技术解析与实战
【10月更文挑战第13天】Netty是一个异步事件驱动的网络应用程序框架,由JBOSS提供,现已成为Github上的独立项目。
58 0

推荐镜像

更多