0

0

浅谈 Node.js 中间件的工作原理

PHPz

PHPz

发布时间:2020-09-25 15:47:33

|

2976人浏览过

|

来源于segmentfault

转载

浅谈 Node.js 中间件的工作原理

什么是 Express 中间件?

  • 中间件在字面上的意思是你在软件的一层和另一层中间放置的任何东西。
  • Express 中间件是在对 Express 服务器请求的生命周期内所执行的函数。
  • 每个中间件都可以访问其被附加到的所有路由的 HTTP 请求和响应。
  • 另外,中间件可以终止 HTTP 请求,也可以用 next 将其传递给另一个中间件函数。中间件的这种“链”使你可以对代码进行划分并创建可重用的中间件。

编写 Express 中间件的要求

你需要安装一些东西来创建、使用和测试 Express 中间件。首先需要 Node 和 NPM。为确保已经安装,可以运行:

npm -v && node -v

你应该看到已安装的 Node 和 NPM 版本。如果出现错误,则需要安装 Node。所有例子都应在 Node ver 8+ 和NPM ver 5+ 下使用。

本文使用了 Express 4.x 版。这很重要,因为从 3.x 版到 4.x 版有重大的更改。

Express中间件:基础

首先我们使用 Express 最基本的内置中间件。创建一个新项目并 npm 初始化它…

npm init
npm install express --save

Create server.js and paste the following code:

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

app.get('/', (req, res, next) => {
  res.send('Welcome Home');
});

app.listen(3000);

中间件解决什么问题?为什么要用它?

假设你在 web 网络服务器上正在使用 Node.js 和 Express 运行Web应用程序。在此应用中,你需要登录的某些页面。

当 Web 服务器收到数据请求时,Express 将为你提供一个请求对象,其中包含有关用户及其所请求数据的信息。 Express 还使你可以访问响应对象,可以在Web服务器响应用户之前对其进行修改。这些对象通常缩短为 reqres

中间件函数是使用相关信息修改 reqres 对象的理想场所。例如用户登录后,你可以从数据库中获取其用户详细信息,然后将这些详细信息存储在 res.user 中。

中间件函数是什么样的?

async function userMiddleware (req, res, next) {
    try {
        const userData = await getUserData(req.params.id);  //see app.get below

        if(userData) {
                req.user = userData;
                next();
        }
    } catch(error)  {
        res.status(500).send(error.message); //replace with proper error handling
    }
}

如果出现错误,并且你不想执行其他代码,则不要调用该函数。请记住在这种情况下要发送响应,否则客户端将会等待响应直到超时。

var app = express();

//your normal route Handlers
app.get('/user/:id', userMiddleware, userController);

中间件链

你可以在中间件数组中或着通过使用多个 app.use 调用来链接中间件:

app.use(middlewareA);
app.use(middlewareB);
app.get('/', [middlewareC, middlewareD], handler);

Express 收到请求后,与请求相匹配的每个中间件都将会按照初始化的顺序运行,直到有终止操作为止。

1.png

因此,如果发生错误,则将按顺序调用所有用于处理错误的中间件,直到其中一个不再调用 next() 函数调用为止。

商务通(在线客服系统)
商务通(在线客服系统)

一款无需安装的即时交流系统,只需申请一个帐号,将一段代码嵌入贵站网页中,就可以让客服人员发现所有到达您网站的访客,而且可以看到访客的来源、使用的搜索引擎等,您可以主动发起对话与访客沟通,进行产品推销,从而大大提高产品销售成功率。 还是一款协同管理软件,在保持与客户信息通畅的同时,也保持公司内部之间的信息交流,从而提高企业的工作效率和客户服务质量。 管理员帐号:biiz.cn 密码:biiz.cn

下载

Express中间件的类型

  • 路由器级中间件,例如:router.use
  • 内置中间件,例如:express.static,express.json,express.urlencoded
  • 错误处理中间件,例如:app.use(err,req,res,next)
  • 第三方中间件,例如:bodyparser、cookieparser
  • 路由器级中间件
  • express.Router 使用 express.Router 类创建模块化的、可安装的路由处理。路由实例是一个完整的中间件和路由系统。

    • 你可以用中间件进行日志记录、身份验证等操作。如下所示,以记录用户的最新活动并解析身份验证标头,用它确定当前登录的用户并将其添加到 Request 对象。
    • 该函数在程序每次收到请求时执行。如果有错误,它会仅结束响应,而不会调用后续的中间件或路由处理。
var router = express.Router()
//Load router-level middleware by using the router.use() and router.METHOD() functions.
//The following example creates a router as a module, loads a middleware function in it,
//   defines some routes, and mounts the router module on a path in the main app.
var express = require(‘express’);
var router = express.Router();

// a middleware function with no mount path. This code is executed for
//   every request to the router
// logging
async function logMiddleware (req, res, next) {
    try {
         console.log(req.user.id, new Date());
     next();
    } catch() {
        res.status(500).send(error.message);
    }
}
// authentication
    async function checkAuthentication(req, res, next) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token || req.headers['x-access-token']
 || req.headers['authorization'];
      if (token) {
        try {
            // verifies secret
            req.decoded = await jwt.verify(token, config.secret)

            let checkUser = await authenticateTokenHelper.getUserDetail(req);

            // if everything is good, save to request for use in other routes
                if (checkUser) {
                        req.user = req.decoded
                        next()
                } else {
                    return res.status(403).json({ 
                    message: responseMessage.noAuthorized 
                    })
                }
        } catch (err) {
            return res.status(401).json({ message: responseMessage.invalidToken })
        }
  } else {
    // if there is no token
    return res.status(400).json({ message: responseMessage.invalidRequest })
  }
}
router.use(logMiddleware);
    router.get('/user, checkAuthentication, handler);

内置中间件

Express 有以下内置的中间件功能:

  • express.static 提供静态资源,例如 HTML 文件,图像等。
  • express.json 负载解析用 JSON 传入的请求。
  • express.urlencoded 解析传入的用 URL 编码的有效载荷请求。

错误处理中间件

错误处理中间件始终采用四个参数(err,req,res,next)。你必须通过提供四个参数来将其标识为错误处理中间件函数。即使你不需要使用 next 对象,也必须指定。否则 next 对象将被解释为常规中间件,并将会无法处理错误。基本签名如下所示:

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

例1:

app.get('/users', (req, res, next) => {
  next(new Error('I am passing you an error!'));
});
app.use((err, req, res, next) => {
  console.log(err);    
  if(!res.headersSent){
    res.status(500).send(err.message);
  }
});

在这种情况下,管道末端的错误处理中间件将会处理该错误。你可能还会注意到,我检查了 res.headersSent 属性。这只是检查响应是否已经将标头发送到客户端。如果还没有,它将向客户端发送 HTTP 500  状态和错误消息。

例2:

你还可以链接错误处理中间件。通常以不同的方式处理不同类型的错误:

app.get('/users, (req, res, next) => {
  let err = new Error('I couldn\'t find it.');
  err.httpStatusCode = 404;
  next(err);
});

app.get('/user, (req, res, next) => {
  let err = new Error('I\'m sorry, you can\'t do that, Dave.');
  err.httpStatusCode = 304;
  next(err);
});

app.use((err, req, res, next) => {
   // handles not found errors
  if (err.httpStatusCode === 404) {
    res.status(400).render('NotFound');
  }
   // handles unauthorized errors 
  else if(err.httpStatusCode === 304){
    res.status(304).render('Unauthorized');
  }
    // catch all
   else if (!res.headersSent) {
     res.status(err.httpStatusCode || 500).render('UnknownError');
  }
  next(err);
});
  • 在这种情况下,中间件检查是否抛出了 404(not found)错误。如果是,它将渲染 “NotFound” 模板页面,然后将错误传递到中间件中的下一项。
  • 下一个中间件检查是否抛出了 304(unauthorized)错误。如果是,它将渲染“Unauthorized”页面,并将错误传递到管道中的下一个中间件。
  • 最后,“catch all” 错误处理仅记录错误,如果未发送响应,它将发送错误的 httpStatusCode(如果未提供则发送 HTTP 500 状态)并渲染 “UnknownError” 模板。

第三方级别的中间件

在某些情况下,我们将向后端添加一些额外的功能。先安装 Node.js 模块获取所需的功能,然后在应用级别或路由器级别将其加载到你的应用中。

示例:当 body-parser 处理 Content-Type 请求标头时,所有中间件都将使用解析的正文填充 req.body 属性。

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
app.post('/save',(req,res)=>{
    res.json({
        "status":true,
         "payload":req.body
    })
}
app.listen(3000,(req,res)=>{
    console.log('server running on port')
})

总结

中间件功能是一种非常好的方式,可以对每个请求或针对特定路由的每个请求运行代码,并对请求或响应数据采取措施。中间件是现代 Web 服务器的重要组成部分,并且非常有用。

英文原文地址:https://www.thirdrocktechkno.com/blog/how-Node-JS-middleware-works/为了保证的可读性,本文采用意译而非直译。

更多编程相关知识,请访问:编程入门!!

相关专题

更多
node.js调试
node.js调试

node.js调试可以使用console.log()输出调试信息、断点调试和第三方调试工具。详细介绍:1、console.log()输出调试信息,通过在代码中插入console.log()语句,开发人员可以在控制台输出变量的值、函数的执行结果等信息,以便观察代码的执行流程和状态;2、断点调试,可以在代码中设置断点,以便在特定位置暂停代码的执行,观察变量的值和执行流程等。

347

2023.09.19

JavaScript 全栈开发基础(Node.js + 前端)
JavaScript 全栈开发基础(Node.js + 前端)

本专题系统介绍 JavaScript 在全栈开发中的核心知识结构,涵盖 Node.js 基础、Express/Koa 接口构建、前端交互设计、模块化与包管理、数据库连接、前后端数据通信与部署流程。通过完整项目示例,帮助学习者掌握从浏览器到服务器的一体化开发能力,实现真正意义上的全栈入门。

96

2025.11.26

什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

178

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

214

2025.12.18

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

418

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

76

2025.09.10

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

58

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 9.3万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2万人学习

Node.js-前端工程化必学
Node.js-前端工程化必学

共19课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号