nodejs之express中间件

javascript/jquery

浏览数:10

2020-5-23

AD:资源代下载服务

前言

目前最主流的nodejs框架应该就是express和koa了,二者都是同一个团队开发的。koa更新一点,并且一些设计思想要比express更成熟,不过仍有大量的项目在使用express。
作者对于express框架的定义为“==基于 Node.js 平台,快速、开放、极简的 Web 开发框架==”。说明express框架本身并没有太多功能,而其大多功能都是通过中间件实现的。由此可见中间件在express中的重要性。

何为中间件?

当客户端的请求到达服务器后,nodejs会为请求创建一个请求对象叫request,该对象上包含了请求的信息以及客户端传来的数据。同时也会创建一个响应对象-response,响应对象主要负责将服务器处理的结果返回给客户端。那么在服务端响应结果之前就可以插入多个中间件。中间件就可以理解成一个对请求进行过滤和预处理的东西,但他不会直接对客户端进行响应,而是将处理之后的结果向下传递,这也就是为什么可以插入多个中间件了。

在早先的express版本中,中间件使用了Connect中间件框架,3.0版本的express就移除了除‘express.static’外的全部内置中间件,而在4.0版本的express框架中已经不在依赖Connect。可以说新版的express是一个独立的路由和中间件的web框架。

使用中间件

除了使用express.static外的其他中间件都需要安装,
npm i <MiddleWare-name> -D
然后在应用中引入中间件:const mod = require('MiddleWare-name');
按照文档描述使用中间件:server.use(……);

下面来看看中间件具体的使用

express.static
先来看唯一一个express内置的中间件——static,static中间件是用来处理文件请求的。

const express = require('express');

let server = express();
server.listen(8080);

server.get('/reg', (req, res, next) => {
  res.send('ok');
});

server.use(express.static('./static/'));

通过server.use使用中间件,在express.static中传入文件路径,在客户端发起文件请求时,服务器就会在该路径下查找对应文件。
注意一点,该中间件一般放到最后使用,因为如果放在路由之前,那么一旦有与接口名字相同的文件请求时,就会先请求文件,这样就不会走到路由中去了。

body-parser
body-parser是帮助解析post数据的中间件,首先需要安装中间件
npm i body-parser -D

const express = require('express');
// 1
const body = require('body-parser');

let server = express();
server.listen(8080);

// 2
server.use(body.urlencoded({
  extended: false // 是否开启扩展模式
}));

// 3
server.post('/reg', {req, res} => {
    let { name, pwd } = req.body;
    res.send('ok');
})
  1. 引入中间件;
  2. 这个中间件的使用就要放到路由之前了,因为它是对请求数据的处理;
  3. 使用了该中间件后,请求对象req上就会多出一个body属性,body属性装载的就是请求的数据。通过body就可以拿到请求的参数;

到这里我们演示两个比较重要和常用的第三方中间件,掌握如何使用中中间件之后(就是调用”server.use(…)” )。其他第三方中间件的使用就大同小异了,至于为什么express.static中间件是调用express.static(),而body-parser中间件是调用body.urlencoded(),这就是作者要求的了,具体调用方式和配置参数还要参考文档。

next方法

express的中间件模式与koa的是不一样的,koa是洋葱型,express是直线型。
在express中间件函数中有三个参数,分别是req、res、next。前两个参数前面有提到过。而最后一个参数next是一个方法,因为一个应用中可以使用多个中间件,而要想运行下一个中间件,那么上一个中间件必须运行next()。

其实express中间件的原理很简单,express在内部维护一个数组,这个数组盛放的是在发出响应之前要执行的所有函数,也可以理解为中间件数组,每一次use以后,传进来的中间件就会放到到数组中,执行完毕后调用next方法执行数组的下一项,如果没有下一项,那么调用就会终止。

大家可能会有疑问,为什么上面使用的两个中间件并没有看到调用next(),但是程序也可以一直向下走呀?那是因为上面的两个中间件是属于内置和第三方中间件,在其封装好的代码中作者已经将next的调用写了进去,中间件执行完已经调用了next(),只不过我们作为使用者看不到而已。下面通过一个我们自己写的中间件实现的简易body-parser功能更清楚的了解next的使用。

手写中间件,实现简版body-parser

当我们可以熟练的使用第三方中间件的时候就要考虑如何自己写一个中间件。其实实现起来并不难,下面就是一个简版的body-parser中间件的实现过程。
1.首先在项目中创建一个libs目录,在目录中创建一个body-parser.js文件。注意这里我们不再需要安装body-parser。

const querystring = require('querystring');

module.exports = {
  // 为了模拟第三方中间件的调用方式,这里也使用urlencoded包裹
  urlencoded() {
    return (req, res, next) => {
      let arr = [];
      req.on('data', buffer => {
        arr.push(buffer);
      });
      req.on('end', () => {
        let post = querystring.parse(Buffer.concat(arr).toString());
        // 讲解析好的数据放到req对象的body属性上
        req.body = post;
        // 调用next方法结束当前中间件的调用,执行后续的操作
        next();
      });
    };
  }
};

2.然后在server.js中引入我们写的中间件,这里的body-parser就不是第三方的body-parser了,而是我们自己写的body-parser。

const express = require('express');
const body = require('./libs/body-parser');

let server = express();
server.listen(8080);

server.use(body.urlencoded());

server.post('/reg', (req, res, next) => {
  console.log(req.body);
  res.send('ok');
});

server.use(express.static('./'));

3.然后在项目根目录创建user.html文件,内部实现一个简单的form表单

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form class="" action="http://localhost:8080/reg" method="post">
      <input type="text" name="user" value="">
      <input type="password" name="pass" value="">
      <input type="submit" name="" value="注册">
    </form>
  </body>
</html>

4.最后启动服务
node server.js
在浏览器中访问 http://localhost:8080/user.html
填写表单,点击提交按钮,查看在命令行中查看。

表单提交的数据成功被解析并且打印到命令行中了。

这样一个最简版的body-parser中间件就实现了,其实内部就是对post请求数据的解析处理。当然第三方的中间件里面的逻辑处理要比我们实现的复杂很多,不过原理都是一样的。

底层原理(Connect框架)

其实express中间件的实现依赖了Connect中间件框架,也就是说早先版本的express框架的中间件完全是由另一个独立的框架Connect实现的,Connect也是express框架的作者编写的。在express3.0版本中是包含了Connect框架的。而4.0版本中已经移除了对Connect的依赖,在内部实现了Connect接口。

Connect框架的源码写的还是非常经典的,next的设计尤为巧妙,简单易懂。本篇只是对中间件的使用的介绍,并且还告诉大家如何自己写中间件。如果对Connect的底层实现有兴趣,请看下篇文章。《nodejs之中间件框架Connect源码浅谈》

作者:巴斯光年