likes
comments
collection
share

从“请求-响应循环”理解Express中间件,通俗易懂!

作者站长头像
站长
· 阅读数 10

在接触Express中间件时,发现许多博客和资料上来就是列概念和做案例,普遍存在用2*2去解释1+1的问题。如标题所说,在学习中间件Middleware)的概念之前,非常有必要先了解一下请求-响应循环Request-Response Cycle)。因为它其实是Express开发的根本所在。

请求—响应循环

从“请求-响应循环”理解Express中间件,通俗易懂!

不要被这个名字唬到了,请求-响应循环其实就是客户端向服务端发送网络请求,并接收响应的过程。因为那个经典的面试问题——输入url😮,这个过程我们再熟悉不过了,但它说复杂也再复杂不过了。不过那些都不是我们现在要关注的,我们关注的是Express在其中的作用,准确说是中间件在其中扮演了什么角色。我们通过下面这张图来理解: 从“请求-响应循环”理解Express中间件,通俗易懂! 简单来说,中间件就是在请求-响应的过程中给我们提供一个可以修改内容的机会。中间件的这个中间说的是请求(Request)和响应(Response)的中间,从功能上看,中间件就是一个可以处理请求和响应内容的函数。Express应用程序本质上就是一系列中间件函数的调用过程,维系着这个调用的是每个中间件内的next()函数。

中间件堆栈

以上涉及的所有中间件维持着一个中间件堆栈(Middleware Stack),它们的执行顺序完全取决于在代码中定义时的顺序,首先在代码中出现的中间件将首先执行。也就是说,整个执行过程其实是线性的。

现在我们来梳理一下Express中从发出请求到返回响应的整个过程:

首先,Express会构建出requestresponse对象;之后,这俩对象会遍历每个程序中的每个中间件,在每个中间件中它们可能会被处理或者执行其它的代码,在每个中间件的最后会调用next()函数来将控制权交给下一个中间件,最后一个中间件通常是处理路由(router)的,因此没有调用下一个中间件,而是将响应数据返回给客户端。最终,完成了一次请求—响应循环。

我们可以将上述过程看作一个数据从请求传输到最终响应的管道(Pipeline)。这样就更直观了。

最小实践

我们使用app.use方法来在Express中注册中间件,在之前的文章中,我们使用Express发送POST请求时,就用到了app.use(express.json())来创建一个最普通的中间件,通过app.use注册的中间件,无论请求方式是什么,请求路径是什么,它都会被执行。事实上Express中所有东西都是中间件,比如app.get()app.post()也只是针对特定的请求方式和路径。

app.use接收req, resnext三个参数,在app.js中输入以下代码:

// app.js
const express = require('express');
const app = express();

app.use((req, res, next) => {
  console.log('middleware 1');
  next();
});

app.use((req, res, next) => {
  console.log('middleware 2');
  next();
});

app.listen(3000, () => {
  console.log('App running at port 3000');
});

Postman我中使用任意一种方式向127.0.0.1:3000发送请求,可以看到控制台输出如下:

从“请求-响应循环”理解Express中间件,通俗易懂!

下面对代码做些改动:

app.use((req, res, next) => {
  console.log('middleware 1');
  next();
});

app.use((req, res, next) => {
  console.log('middleware 2');
  next();
});

app.get('/', (req, res) => {
  console.log('middleware get');
  res.send('Hello from server');
});

此时控制台的输出:

从“请求-响应循环”理解Express中间件,通俗易懂!

可以看到app.get()方法本身就是中间件,只是应用于特定的URL。而使用app.use()所创建的中间件响应所有请求,因为它们是在含有res.send()方法的中间件之前定义的。 我们可以调整一下代码的顺序:

app.use((req, res, next) => {
  console.log('middleware 1');
  next();
});

app.get('/', (req, res) => {
  console.log('middleware get');
  res.send('Hello from server');
});

app.use((req, res, next) => {
  console.log('middleware 2');
  next();
});

从“请求-响应循环”理解Express中间件,通俗易懂!

由于app.get()中使用了res.send()来结束127.0.0.1:3000这个URL的请求—响应循环,所以第二个中间件不会被执行。