nodejs篇 express(2) 中间件详解

前言

在这里插入图片描述

上一篇文章中,简单介绍了express.js的使用,nodejs篇 express(1),其中提到了express中间件的使用。其实,在项目开发的过程中,使用express.js搭建的服务器,中间件的作用无处不在。

不同的应用场景和不同的调用方式,中间件可以分为以下几个类别:应用程序级别的中间件、路由级别的中间件、错误处理中间件、内置中间件、第三方中间件。学完之后呢,你就会对express中间件的应用得心应手。

应用程序级别的中间件

全局中间件

这类中间件的作用范围包含整个服务器的所有接口,不关心请求的具体路由,也不关心请求的方法是什么,只要是请求的服务器地址和端口号没有错,都会执行的中间件函数。

示例

var express = require("express");
var APP = express();
var PORT = 3000;

function getOriginalUrl() {
    
    
  return function (req, res, next) {
    
    
    console.log(req.originalUrl);
    next();
  }
}

APP.use(getOriginalUrl());

APP.post("/api", function (req, res) {
    
    
  res.set("Content-Type", "application/json");
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

APP.get("/user/:id", function (req, res) {
    
    
  res.set("Content-Type", "application/json");
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

如上面的代码所示,无论客户端请求api还是user/:id,都会调用getOriginalUrl方法,将请求的路由打印出来。

限定请求路径的中间件

针对特定的符合某一规则的路径,进行的函数封装处理。

var express = require("express");
var APP = express();
var PORT = 3000;

function getParams() {
    
    
  return function (req, res, next) {
    
    
    console.log(`动态路由`, req.params);
    next();
  };
}

// 只针对路径是/user/:id的中间件
APP.use("/user/:id", getParams());

APP.get("/user/:id", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

上述示例是只针对路径是/user/:id的中间件,当然use函数第一个参数不仅可以传低一个字符串,还可以传递一个正则,只要符合要求就会执行中间件。

限定请求方法和请求路径的中间件

这种是最常用的一种中间件使用方式

var express = require("express");
var app = express();
var port = 3000;

// express.json 就是中间件,用来处理客户端发送json数据在body中接收
app.post("/api", express.json(), function (req, res) {
    
    
  console.log(req.body)
  res.set("Content-Type", "application/json");
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

app.listen(port, function () {
    
    
  console.log("server runing at 3000");
});

多个处理中间件

上面介绍的全局中间件或者是限定请求路径的中间件,或者是限定请求路径和请求方法的中间件,都可以一次性传入多个中间件。这些中间件在next() 执行后,就能够依次进行链式调用。

var express = require("express");
var APP = express();
var PORT = 3000;

function getOriginalUrl() {
    
    
  return function (req, res, next) {
    
    
    console.log(req.originalUrl, req.body);
    next();
  };
}

function setContentType(type) {
    
    
  return function(req,res,next) {
    
    
    res.set("Content-Type", type);
    next()
  }
}

// 全局使用多个中间件示例
APP.use(express.json(), getOriginalUrl(), setContentType("application/json"));

// 限定路径使用多个中间件示例
APP.use("/user/:id", express.json(), getOriginalUrl(), setContentType("application/json"));

// 限定路径和方法使用多个中间件示例
APP.get("/user/:id",express.json(), getOriginalUrl(), setContentType("application/json"), function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

感觉上面的写法还是有些麻烦,我们可以简化下

var express = require("express");
var APP = express();
var PORT = 3000;

function getOriginalUrl() {
    
    
  return function (req, res, next) {
    
    
    console.log(req.originalUrl, req.body);
    next();
  };
}

function setContentType(type) {
    
    
  return function(req,res,next) {
    
    
    res.set("Content-Type", type);
    next()
  }
}

var middlewares = [getOriginalUrl(), setContentType("application/json"), express.json()]

// 全局使用多个中间件示例
APP.use(middlewares);

// 限定路径使用多个中间件示例
APP.use("/user/:id", middlewares);

// 限定路径和方法使用多个中间件示例
APP.get("/user/:id", middlewares, function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

如果多个中间件,在某些情况下,我只想执行前两个中间件,不想执行第三个中间件,如何处理?

function getOriginalUrl() {
    
    
  return function (req, res, next) {
    
    
    console.log(req.originalUrl, req.body);
    next();
  };
}

function setContentType(type) {
    
    
  return function (req, res, next) {
    
    
    res.set("Content-Type", type);
    // get请求时不接收前端传递过来的body参数,所以不需要处理客户端放在body中的json数据,也就是不需要express.json()
    if (req.method === "GET") {
    
    
      // 将会结束本次app.use的调用,跳过express.json()
      next("route");
    }
    next();
  };
}

var middlewares = [
  getOriginalUrl(),
  setContentType("application/json"),
  express.json(),
];

APP.use(middlewares);

路由级别的中间件

新建一个router.js,代码如下

var express = require("express");

// 创建路由实例
const router = express.Router();

// 配置路由
router.get("/user/:id", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

router.delete("/user/:id", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

router.post("/user", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

// 导出路由
module.exports = router;

在index.js中引入router,并绑定

var express = require("express");
var APP = express();
var PORT = 3000;

var router = require('./router');

function getParams() {
    
    
  return function (req, res, next) {
    
    
    console.log(`动态路由`, req.params);
    next();
  };
}

APP.use("/user/:id", getParams());

// 挂载路由
APP.use(router)

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

当然,如果一系列全是user开头的路径,我们可以适当改造以下

router.js中

var express = require("express");

// 创建路由实例
const router = express.Router();

// 配置路由
router.get("/:id", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

router.delete("/:id", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

router.post("/", function (req, res) {
    
    
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});

// 导出路由
module.exports = router;

index.js中

var express = require("express");
var APP = express();
var PORT = 3000;

var router = require('./router');

function getParams() {
    
    
  return function (req, res, next) {
    
    
    console.log(`动态路由`, req.params);
    next();
  };
}

APP.use("/user/:id", getParams());

// 挂载路由
APP.use("/user", router);

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

改造完成的效果跟之前是一样的

错误处理中间件

var express = require("express");
var APP = express();
var PORT = 3000;

APP.delete("/user/:id", function (req, res, next) {
    
    
  if (req.params.id === "0") {
    
    
    next({
    
    
      message: "该用户不存在"
    });
  }
  res.status("200");
  res.json({
    
     code: 200, data: "请求成功了" });
});


// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
    
    
  console.log("出错了", error.message);
  res.status("500");
  res.json({
    
    
    message: error.message,
  });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

配置错误处理中间件的注意事项

  1. 四个参数的函数(一个都不能少),会被express认为是错误处理中间件
  2. 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
  3. error与后面三个参数不同,是自定义的,与之前next(errprParams) 有关

调用错误处理中间件

  1. 只需要在next中传递非'route'的参数
  2. next(params), 其中params就是错误处理中间件的第一个参数error
  3. next()、next('route')、next(非route) next有这三种调用方式,但功能各不相同,next()就是走下一个中间件,next('route') 就是跳过接下来同一个app.use(app.get等)调用的多个后面的中间件,next(非route)就是调用错误中间件

中间件处理404

状态码404比较特殊,它表示客户端请求的路由在服务器里没有匹配,因此,在express项目中,我们一般都需要在所有路由配置的最后,用中间件处理404的情况。

中间件处理404和错误处理中间件之间互不影响。

var express = require("express");
var APP = express();
var PORT = 3000;

var router = require("./router");

// 挂载路由
APP.use(router);

// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
    
    
  res.status('404').send("404 not found")
});

// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
    
    
  console.log("出错了", error.message);
  res.status("500");
  res.json({
    
    
    message: error.message,
  });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

内置中间件

express 4.x以后,内置中间件被缩减到了五个,它们分别是

  1. express.json 解析Content-Type 为application/json 格式的请求体
  2. express.raw 解析Content-Type 为octet-stream 格式的请求体
  3. express.text 解析Content-Type 为text/plain 格式的请求体
  4. express.urlencoded 解析Content-Type 为x-www-form-urlencoded格式的请求体
  5. express.static 托管静态资源文件

比较常用的,其实就是 json urlencoded static
express.json 当客户端给你发送json数据时,需要在express中使用这个中间件后,才能在req.body中拿到数据
express.urlencoded 当客户端以表单的形式发送请求时,需要使用这个中间件。
express.static 当客户端向服务端发送文件时,需要使用

express官方介绍内置中间件地址

使用方式,一般在最上方使用常用的二个内置中间件

var express = require("express");
var APP = express();
var PORT = 3000;

var router = require("./router");

//设置允许跨域访问该服务.
APP.all("*", function (req, res, next) {
    
    
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Content-Type");
  res.header("Access-Control-Allow-Methods", "*");
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

// 调用内置中间件
var middlewares = [
  express.json(),
  express.urlencoded()
];
APP.use(middlewares);

// 挂载路由
APP.use(router);

// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
    
    
  res.status('404').send("404 not found")
});

// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
    
    
  console.log("出错了", error.message);
  res.status("500");
  res.json({
    
    
    message: error.message,
  });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

第三方中间件

express官方维护了一些第三方中间件以及推荐的一些第三方中间件
https://expressjs.com/en/resources/middleware.html

以其中一个第三方中间件morgan为例,打印响应日志的一个中间件。

安装

npm install morgan

使用

var express = require("express");
var morgan = require("morgan");
var APP = express();
var PORT = 3000;

var router = require("./router");

//设置允许跨域访问该服务.
APP.all("*", function (req, res, next) {
    
    
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Content-Type");
  res.header("Access-Control-Allow-Methods", "*");
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

var middlewares = [express.json(), express.urlencoded()];

APP.use(middlewares, morgan(':method :url :status :res[content-length] - :response-time ms'));

// 挂载路由
APP.use(router);

// 404中间件处理,由于之前的所有router都没匹配到,前面的中间件都没有回复响应,我们需要这个中间件做兜底处理。
APP.use((req, res) => {
    
    
  res.status("404").send("404 not found");
});

// 错误处理中间件,四个参数的函数,会被express认为是错误处理中间件
// 调用的位置,一般是在所有接口的后面,这样就能够拦截前面所有路径抛出的异常
// error与后面三个参数不同,是任意的,与之前next(errprParams) 有关
APP.use(function (error, req, res, next) {
    
    
  console.log("出错了", error.message);
  res.status("500");
  res.json({
    
    
    message: error.message,
  });
});

APP.listen(PORT, function () {
    
    
  console.log(`server runing at ${
      
      PORT}`);
});

nodejs相关其它内容

nodejs commonjs介绍
nodejs fs模块介绍
nodejs path模块介绍
nodejs events模块介绍
nodejs http模块介绍
nodejs net模块介绍
nodejs url模块介绍
nodejs process模块介绍
nodejs buffer模块介绍
nodejs stream 模块介绍
nodejs express(1)模块介绍

猜你喜欢

转载自blog.csdn.net/glorydx/article/details/129814496