详解Node.js中间件是怎样工作的

 更新时间:2021年04月30日 10:06:36   作者:浅笑·  
这篇文章主要介绍了详解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服务器响应用户之前对其进行修改。这些对象通常缩短为req,res。

中间件函数是使用相关信息修改req和res对象的理想场所。例如用户登录后,你可以从数据库中获取其用户详细信息,然后将这些详细信息存储在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 收到请求后,与请求相匹配的每个中间件都将会按照初始化的顺序运行,直到有终止操作为止。

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

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 服务器的重要组成部分,并且非常有用。

以上就是详解Node.js中间件是怎样工作的的详细内容,更多关于Node.js中间件的资料请关注脚本之家其它相关文章!

相关文章

  • Node.js的环境安装配置(使用nvm方式)

    Node.js的环境安装配置(使用nvm方式)

    在我们前端开发工程中,很多繁琐机械的操作都是会慢慢的被抽离出来的,比如当我们为dom操作和浏览器兼容性感到厌烦时,jQuery出现了,随着时间的发展,JavaScript现在被应用到了服务器中,但是首先第一步我们要学会如何安装配置Node.js的环境,本文是使用nvm方式,来一起看看。
    2016-10-10
  • 利用nodeJs anywhere搭建本地服务器环境的方法

    利用nodeJs anywhere搭建本地服务器环境的方法

    今天小编就为大家分享一篇利用nodeJs anywhere搭建本地服务器环境的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-05-05
  • nodejs使用socket5进行代理请求的实现

    nodejs使用socket5进行代理请求的实现

    这篇文章主要介绍了nodejs使用socket5进行代理请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • 详解node.js搭建代理服务器请求数据

    详解node.js搭建代理服务器请求数据

    本篇文章主要介绍了详解node.js搭建代理服务器请求数据,具有一定的参考价值,有兴趣的可以了解一下。
    2017-04-04
  • VsCode与Node.js知识点详解

    VsCode与Node.js知识点详解

    在本篇文章中小编给大家分享了关于VsCode与Node.js的相关知识点以及安装等内容,需要的朋友们可以参考下。
    2019-09-09
  • 用nodejs的实现原理和搭建服务器(动态)

    用nodejs的实现原理和搭建服务器(动态)

    下面小编就为大家带来一篇用nodejs的实现原理和搭建服务器(动态)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • mongoose更新对象的两种方法示例比较

    mongoose更新对象的两种方法示例比较

    最近在使用mongoose的时候发现了一个之前一直没注意的知识点,下面这篇文章主要给大家介绍了关于mongoose更新对象的两种方法,通过示例代码将两种方法进行详细的对比,以给大家更好的参考学习,需要的朋友可以参考下。
    2017-12-12
  • node.js中的console.info方法使用说明

    node.js中的console.info方法使用说明

    这篇文章主要介绍了node.js中的console.info方法使用说明,本文介绍了console.info的方法说明、语法、接收参数、使用实例和实现源码,需要的朋友可以参考下
    2014-12-12
  • 基于Node.js的大文件分片上传示例

    基于Node.js的大文件分片上传示例

    这篇文章主要介绍了基于Node.js的大文件分片上传示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • 手把手教你使用TypeScript开发Node.js应用

    手把手教你使用TypeScript开发Node.js应用

    为了减少代码编写过程中出现的错误,以及更好的维护你的项目,本文将手把手教你配置一个简单的开发环境来编写Node.js的应用程序,感兴趣的小伙伴们可以参考一下
    2019-05-05

最新评论