Nodejs之学习Express 路由与中间件

一、路由的概念

1、路由就是映射关系

生活实例:在我们拨打10086客服电话时,对应的每个按键有不同的功能,比如按键1-> 服务查询,按键2-> 手机充值,在这里,路由是按键服务之间的映射关系。
在Express中,路由指的是客户端的请求服务器处理函数之间的函数关系。Express中路由由3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:

app.method(path,handler)

express中路由的例子

//匹配 get 请求,且请求URL为/
app.get('/',function(req,res)=>{
     res.send('hello express')
 })
 //匹配 post 请求,且请求URL为/
 app.post('/',function(req,res)=>{
     res.send('hello listpage')
 })

2、路由的匹配过程

每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。在匹配时,会按照路由的先后顺序进行匹配,如果请求类型请求的URL 同时匹配成功,则Express 会将这次请求,转交给对应的 function 函数进行处理。

二、路由的使用

1、路由的简单用法

//1导入 express
const .express = require('express') 
//2.创建 web 服务器
const app = express()
//挂载路由
app.get('/',(req,res)=>{
    res.send('hello')
})
app.post('/',(req,res)=>{
    res.send('post request')
 })
//3.启动 web 服务器.
app.listen(80,()=>{
    console.log('服务器运行在80端口');
})

如果挂载多个路由这个方式会很不友好。

2、模块化路由

为了方便对路由进行模块化管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。

1)创建路由模块

  • 创建路由模块对应的js文件。
  • 调用express.Router()函数创建路由对象。
  • 向路由对象上挂载具体的路由。
  • 使用module.exports向外共享路由对象。
  • 使用app.use()函数注册路由模块。
//1.导入 express
const express = require('express') 
//2.创建路由对象
const router = express.Router()
//3.挂载获取用户列表的路由
router.get('/user/list',function(req,res){
    res.send('get user list')
})
//4.挂载添加用户的路由
router.post('/user/add',function(req,res){
    res.send('add new user')
 })
//5.向外导出路由对象
module.exports = router;

如何用外部服务器使用路由模块正常工作?步骤就是先导入在注册,代码如下

2)注册路由模块

const express = require('express');
const app = express()
//导入路由模块
const router = require('./express')
//使用app.use()注册路由模块
app.use(router)
app.listen(80,()=>{
    console.log('http://127.0.0.1');
})

打开postman 进行 get 测试,输入http://127.0.0.1/user/list
在这里插入图片描述

打开postman 进行 post 测试,输入http://127.0.0.1/user/add

在这里插入图片描述
注意:app.use()函数的作用,就是来注册全局中间件

3)为路由模块添加前缀

类似于托管静态资源为静态资源统一挂载访问前缀一样,路由模块添加前缀的方式如下:

const express = require('express');
const app = express()
//导入路由模块
const router = require('./express')
//注册路由模块
app.use('api',router)    //在调用app.use 前添加'api'
app.listen(80,()=>{
    console.log('http://127.0.0.1');
})

再次使用 postman 访问时便发生了变化
在这里插入图片描述

三、Express 中间件

1、中间件的概念与格式

1)什么是中间件

中间件(Middleware),特指业务流程的中间处理环节。
现实生活实例:在处理污水的时候,一般都要经过三个处理环节,从而保证处理过后的废水,达到排放标准。
在这里插入图片描述

处理污水的这三个中间处理环节,就可以叫做中间件。
Express 中间件的调用流程:当一个请求到达express 的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
在这里插入图片描述

2)Express 中间件的格式

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

app.get('/',function(req,res,next){
  next(); 
))
app.listen(3000);

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

3)next 函数的作用

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

4)定义简单中间件函数

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

2、全局生效的中间件

1)中间件函数

客户端发起的任何请求,到达服务器之后,都会被触发的中间件,叫做全局生效的中间件。通过调用app.use(中间件函数),即可定义一个全局生效的中间件,代码如下:

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

 //定义中间件函数
 const mw = function(req,res,next){
    console.log('hello');
    //把流转关系转交给下一个中间件路由
    next() 
}
//全局生效的中间件
app.use(mw)
app.get('/',(req,res)=>{    //调用 ‘/’ 这个路由
	console.log('hi~')
    res.send('home page')
})
app.get('/user',(req,res)=>{   //调用‘/user’ 这个路由
    console.log('success')
    res.send('user page')
})
 app.listen(80,()=>{
    console.log('http://127.0.0.1');
 })

通过postman 测试一下第一个路由:输入http://127.0.0.1/
在这里插入图片描述
经过中间件处理之后通过next 函数把流转关系转交给‘/’ 这个路由`。服务端可以得到以下结果
在这里插入图片描述
通过res.send()响应客户端的请求,从而在客户端得到这样的结果。
在这里插入图片描述
通过postman 测试一下第二个路由:输入http://127.0.0.1/user

同样经过中间件处理之后通过next 函数把流转关系转交给‘/user’ 这个路由`。服务端可以得到以下结果
在这里插入图片描述
同样通过res.send()响应客户端的请求,从而在客户端响应一个文本消息。
在这里插入图片描述

2)全局中间件的简化形式

//这是定义全局中间件的简化形式
app.use(function(req,res,next){
    console.log('最简单的中间件函数');
    next()
})

同样能得到上述结果。

3)中间件的作用

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

在这里插入图片描述

举一个例子:如果我们想要获取到请求到达服务器的时间,传统方法在每个路由里面都添加对现在时间的定义,但是因为用路由的方式需要定义很多次,所以可以使用中间件来简化这个操作。代码如下:

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

app.use(function(req,res,next){
    //获取到请求到达服务器的时间
    const time = Date.now()
    //为req对象,挂载自定义属性,从而把时间共享给后面的所有路由
    req.startTime = time
    next()
})

app.get('/',(req,res)=>{
    // 传统定义时间的方式,需要在每一个路由中都在定义
    //const time = Date.now()
    res.send('home page' + req.startTime)
})
app.get('/user',(req,res)=>{
    res.send('user page' + req.startTime)
})
 app.listen(80,()=>{
    console.log('http://127.0.0.1');
 })

启动终端之后,在postman 中测试,客户端得到了如下结果。
在这里插入图片描述

4)定义多个全局中间件

使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。

const express = require('express')
const app = express();
// 定义第一个全局中间件
app.use(function(req,res,next){
    console.log('调用了第一个全局中间件');
    next()
})

// 定义第二个全局中间件
app.use(function(req,res,next){
    console.log('调用了第二个全局中间件');
    next()
})

//定义一个路由
app.get('/user',(req,res)=>{
    res.send('user page')
})
 app.listen(80,()=>{
    console.log('http://127.0.0.1');
 })

启动终端之后,在postman 中测试,输入http://127.0.0.1/user 服务器端得到了如下结果。
在这里插入图片描述

5)局部生效的中间件

不使用 app.use() 定义的中间件,叫做局部生效的中间件,用法是在“当前路由中生效”。代码如下:

const express = require('express')
const app = express();
//1、定义中间件函数
const mv1 = (req,res,next)=>{
    console.log('调用局部生效的中间件');
    next()
}
//创建路由
app.get('/', mv1,mv2, (req,res)=>{   //加上mv1 就相当于在这个路由中使用了中间件
    res.send('home page')
})
app.get('/user',(req,res)=>{
    res.send('user page')
})
 app.listen(80,()=>{
    console.log('http://127.0.0.1');
 })

启动终端之后,在postman 中测试,输入http://127.0.0.1/user
服务器并不能打印出“调用局部生效的中间件”
当输入http://127.0.0.1/ 客户端得到了如下结果。
在这里插入图片描述

6)定义多个中间件

有两种方式,代码如下:

app.get('/', mv1,mv2, (req,res)=>{ res.send('home page')})
app.get('/', [mv1,mv2], (req,res)=>{ res.send('home page')})

7)了解中间件的5个注意事项

  • 一定要在路由之前注册中间件
  • 客户端发送过来的请求,可以连续调用多个中间件进行处理
  • 执行完中间件的业务代码之后,不要忘记调用next()函数
  • 为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
  • 连续调用多个中间件时,多个中间件之间,共享 req 和 rest 对象。

四、中间件分类

1、应用级别的中间件

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

2、路由级别的中间件

绑定到express.Router()实例上的中间件,叫做路由级别的中间件,它的用法和应用级别中间件没有任何区别,只不过,应用级别中间件是绑定到app实例上,路由级别中间件事件绑定到 router 实例上。

3、错误级别的中间件

错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式:错误级别中间件的function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别为(err,req,res,next

//1.路由
app.get('/',function(req,res){
    //1.1 抛出一个自定义的错误
    throw new Error('服务器内部发生了错误!')
    res.send('home page')
})
app.use((err,req,res,next)=>{
    console.log('发生了错误:' + err.message);
    res.send('Error!'+ err.message)
})

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

4、Express 内置的中间件

三个常见的内置中间件:

  • express.static快速托管静态资源的内置中间件,例如:HTML文件,图片,CSS样式等(无兼容)
  • express.json解析JSON 格式的请求体数据(有兼容性)
  • express.urlencoded 解析URL-encoded 格式的请求体数据(有兼容性)
//解析JSON 格式的请求体数据
app.use(express.json())
//解析URL-encoded 格式的请求体数据
app.use(express.urlencoded({extended:false}))

1)express.json内置中间件的使用:

当我们通过 postman 中成功发送了一部分关于JSON的数据之后,将怎么传输到服务器上进行使用那,比如这种数据
在这里插入图片描述
在服务器中,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据。
注意: 默认情况下,如果不配置解析表单数据的中间件,则req.body 默认等于undefined

const express = require('express')
const app = express();
//通过express.json这个中间件,解析表单中的JSON格式的数据
 app.use(express.json());
//1.路由
app.post('/user',function(req,res){
 //默认情况下,如果不配置解析表单数据的中间件,则req.body 默认等于undefined
    console.log(req.body);
    res.send('ok')
})
app.listen(80,function(){
    console.log('http://127.0.0.1');
})

再次根据postman 请求发送数据,这时候在服务器上就可以看到发送过来的数据了。

在这里插入图片描述

2)express.urlencoded 内置中间件的使用:

当我们通过 postman 中成功发送了一些URL-encoded 格式的数据之后,将怎么传输到服务器上进行使用那, 在服务器端,通过express.urlencoded这个中间件,解析表单中的url-encoded格式,然后数据就可以挂载到 req.body 上。
在这里插入图片描述

const express = require('express')
const app = express();
//通过express.urlencoded这个中间件,解析表单中的url-encoded格式的数据//解析URL-encoded 格式的请求体数据
app.use(express.urlencoded({extended:false}))
//路由
app.post('/book',function(req,res){
//在服务器端,可以通过 req.body 来获取 JSON 格式的表单数据和URL-encoded 格式的数据,   
   console.log(req.body);
    res.send('ok')
})
app.listen(80,function(){
    console.log('http://127.0.0.1');
})

再次根据postman 请求发送数据,这时候在服务器上就可以看到发送过来的数据了。
在这里插入图片描述

5、第三方的中间件

非Express 官方配置的,而是由于第三方开发出来的中间件,叫做第三方中间件。例如 body-parser 这个中间件,来解析请求体数据。使用步骤:

  • 运行npm install body-parser 安装中间件
  • 使用require导入中间件
  • 调用 app.use() 注册并使用中间件
const express = require('express')
const app = express();
//导入解析表单数据的中间件 body-parser
const parser = require('body-parser');
//使用 app.use()注册中间件
app.use(parser.urlencoded({extended:false}))
app.post('/user',function(req,res){
    //默认情况下,如果不配置解析表单数据的中间件,则req.body 默认等于undefined
    console.log(req.boby)
    res.send('ok')
})
app.listen(80,function(){
    console.log('http://127.0.0.1');
})

在 postman 中输入请求体数据如下,
在这里插入图片描述
服务器端通过 body-parser 中间件来解析请求体数据。Express 内置的express.urlencoded 中间件,就是基于body-parser 这个第三方中间件进一步封装出来的。

6、自定义中间件

1)需求描述与实现步骤

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

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

2)定义中间件

使用app.use()来定义全局生效的中间件;

 app.use(function(req,res,next){
 //中间件的业务逻辑
 })

3)监听 req 的data 事件

在中间件中,需要监听 req 对象的 data 事件,来获取客户端发送到服务器的数据,如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割好后分批发送到服务器。所有data 事件可能会被触发多次,每一次触发data事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。

 //1.定义一个str字符串,专门用来存储客户端发送过来的请求体数据
    let str=''
    //2.监听req的data事件
    req.on('data',(chunk)=>{
        str += chunk
    })

4)监听 req 的 end 事件

当请求体数据接收完毕之后,会自动触发 req 的 end 事件。因此,我们可以在req 的 end 事件中,拿到并处理完整的请求体数据

 //监听req 的 end 事件
    req.on('end',()=>{
        // 把str 中存放的完整的请求体数据
        console.log(str);
        // 把字符串格式的请求体数据,解析成对象格式

    })

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

nodejs内置了一个querystring模块,专门用来处理查询字符串,通过这个模块的parse()函数,可以把查询到的字符串解析成对象的格式。

//1.导入处理 querystring 的node.js 内置模块
const qs = require('querystring')
//2.调用 qs.parse()方法,把查询字符串解析为对象
const body = qs.parse(str)

完整代码:


const express = require('express')
const app = express();
const qs = require('querystring')
//解析表单的中间件
app.use((req,res,next)=>{
    //1.定义一个str字符串,专门用来存储客户端发送过来的请求体数据
    let str=''
    //2.监听req的data事件
    req.on('data',(chunk)=>{
        str += chunk
    })
    //3.监听req 的 end 事件
    req.on('end',()=>{
        //3.1 把str 中存放的完整的请求体数据
        console.log(str);
        //3.2 把字符串格式的请求体数据,解析成对象格式
        const body = qs.parse(str)
        console.log(body);
    })
})

app.post('/user',(req,res)=>{
    res.send('ok')
})
app.listen(80,function(){
    console.log('http://127.0.0.1');
})

6)将解析处理的数据对象挂载为 req.body

上游的中间件和下游的中间件及路由之间,共享一份 req 和 res.因此,我们可以将解析出来的数据,挂载为req的自定义属性,命名为req.body,供下游使用。

    req.on('end',()=>{
        //把str 中存放的完整的请求体数据
        console.log(str);
        // 把字符串格式的请求体数据,解析成对象格式
        const body = qs.parse(str)
        //将解析出来的请求体对象,挂载为req.body属性
        req.body = body
        //最后,调用next()属性,执行后续的业务逻辑
        next()
    })
})

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

第一步,新建自定义模块,命名为customerBodyParser,通过module.exports把bodyparse给暴露出去,然后将自定义的中间件函数注册为全局可用的中间件。

//导入nodejs内置的querystring 模块
const qs = require('querystring')
const bodyparser=(req,res,next)=>{
    //1.定义一个str字符串,专门用来存储客户端发送过来的请求体数据
    let str=''
    //2.监听req的data事件
    req.on('data',(chunk)=>{
        str += chunk
    })
    //3.监听req 的 end 事件
    req.on('end',()=>{
        //把str 中存放的完整的请求体数据
        console.log(str);
        // 把字符串格式的请求体数据,解析成对象格式
        const body = qs.parse(str)
        //将解析出来的请求体对象,挂载为req.body属性
        req.body = body
        //最后,调用next()属性,执行后续的业务逻辑
        next()
    })
}
module.exports = bodyparser
const express = require('express')
const app = express()
//1.导入自己封装的中间件模块
const customerBodyParser = require('./use')
//2.将自定义的中间件函数注册为全局可用的中间件
app.use(customerBodyParser )
app.post('/user',(req,res)=>{
    res.send(req.body)
})
app.listen(80,function(){
    console.log('http://127.0.0.1');
})

在postman 中进行测试,输入以下请求内容
在这里插入图片描述
客户端可以得到以下数据:

在这里插入图片描述

服务器中最终也能得到相关数据:
在这里插入图片描述

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Express是一个基于Node.js平台的Web应用程序框架,它提供了一系列强大的功能和工具,使得开发Web应用程序变得更加简单和高效。Express框架具有灵活性和可扩展性,可以轻松地与其他Node.js模块和库集成,同时也支持多种模板引擎和中间件,使得开发者可以根据自己的需求进行定制和扩展。Express框架还提供了丰富的路由和HTTP请求处理功能,使得开发者可以轻松 ### 回答2: Express是一个流行的Node.js Web应用程序开发框架。它提供了一组简单、灵活和易于使用的功能,可以帮助开发人员快速构建高性能的Web应用程序和API。 Express提供了许多有用的功能,包括路由中间件、模板引擎等。通过使用Express,可以轻松地定义应用程序的不同路由,并将请求映射到相应的处理函数中。这使得应用程序的结构更清晰,并且可以更好地组织和管理代码。 Express还提供了中间件的概念,允许开发人员在请求和响应之间执行一些通用的功能。中间件可以用于处理身份验证、日志记录、错误处理等。使用中间件,可以将这些功能分离到单独的模块中,提高了代码的可重用性和可维护性。 另外,Express还支持多种模板引擎,如EJS、Handlebars等。这些模板引擎允许开发人员动态生成HTML页面,并将数据和逻辑与界面分离。使用模板引擎,可以更方便地构建可重用和可扩展的视图。 总的来说,Express是一个强大而灵活的Web应用程序开发框架。它提供了许多功能,简化了Node.js应用程序的开发过程。使用Express,开发人员可以更快速、更高效地构建出高性能的Web应用程序和API。 ### 回答3: Express是一个流行的Node.js Web应用程序框架,它建立在Node.js的核心HTTP模块之上,旨在简化和加速Web应用程序的开发过程。 Express具有简单易用的API,使得创建Web服务器和处理HTTP请求变得容易。它提供了一组强大的功能和中间件,用于处理路由、模板引擎、HTTP请求和响应等。开发者可以使用Express轻松地创建和管理路由,处理GET、POST、PUT等HTTP请求,并返回各种类型的响应。 Express还支持各种模板引擎,如EJS和Handlebars,使得动态生成HTML页面变得简单。通过使用模板引擎,可以将动态数据嵌入到静态HTML页面中,并将结果返回给客户端。 此外,Express还提供了强大的中间件功能,用于处理HTTP请求和响应。中间件是在请求和响应之间执行的函数,用于执行各种任务,如处理身份验证、错误处理、日志记录等。开发者可以将多个中间件链接在一起,以便在请求到达路由处理之前,对请求进行预处理。 Express的优势之一是其灵活性和可扩展性。它允许开发者使用其他Node.js模块和库,以满足特定的需求。开发者可以自由地选择适合他们项目的组件和解决方案,并根据需要对其进行自定义。 总之,Express是一个强大而灵活的Node.js框架,用于快速构建Web应用程序。它提供了丰富的功能和易于使用的API,使得构建高性能的Web应用程序变得简单。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值