作者:thirdrockteam译文:Crazytechnerd原文:https://www.thirdrocktechkno....未经许可严禁转载什么是Express中间件?中间件的字面意思是你放在一层软件和另一层软件之间的任何东西。Express中间件是在请求Express服务器的生命周期内执行的功能。每个中间件都可以访问它所附加的所有路由的HTTP请求和响应。或者,中间件可以终止HTTP请求或使用next将其传递给另一个中间件函数。这个中间件“链”允许您划分代码并创建可重用的中间件。编写Express中间件的要求您需要安装一些东西来创建、使用和测试Express中间件。首先你需要Node和NPM。为确保它已安装,请运行:npm-v&&node-v,您应该会看到已安装的Node和NPM版本。如果出现错误,则需要安装Node。所有示例都应适用于Nodever8+和NPMver5+。本文使用Express版本4.x。这很重要,因为从3.x版到4.x版有重大变化。Express中间件:基础知识首先我们使用Express最基本的内置中间件。创建一个新项目并npm初始化它...npminitnpminstallexpress--saveCreateserver.js并粘贴以下代码:constexpress=require('express');constapp=express();app.get('/',(req,res,next)=>{res.send('欢迎回家');});app.listen(3000);中间件解决什么问题?为什么要使用它?假设您在Web服务器上使用Node.js和Express运行Web应用程序。此应用程序中有某些页面需要您登录。当Web服务器收到数据请求时,Express会给您一个请求对象,其中包含有关用户和他们请求的数据的信息。Express还允许您访问响应对象,该对象可以在Web服务器响应用户之前进行修改。这些对象通常缩写为req、res。中间件函数是用相关信息修改req和res对象的理想场所。例如,当用户登录时,您可以从数据库中获取他们的用户详细信息,然后将这些详细信息存储在res.user中。中间件功能是什么样的?asyncfunctionuserMiddleware(req,res,next){try{constuserData=awaitgetUserData(req.params.id);//查看下面的app.getif(userData){req.user=userData;下一个();}}catch(error){res.status(500).send(error.message);//替换为正确的错误处理}}如果发生错误并且您不想执行其他代码,则不要调用此函数。请记住在这种情况下发送响应,否则客户端将等待响应直到超时。varapp=express();//你的正常路由Handlersapp.get('/user/:id',userMiddleware,userController);中间件链接你可以在中间件数组中或通过使用多个app.use调用链接中间件:app.use(middlewareA);app.use(middlewareB);app.get('/',[middlewareC,middlewareD],handler);Express收到请求后,每个匹配到请求的中间件都会按照初始化的顺序运行,直到终止。因此,如果发生错误,将依次调用所有处理错误的中间件,直到其中一个不再调用next()函数调用。Express中间件的种类Router级中间件,eg:router.use内置中间件,eg:express.static,express.json,express.urlencoded错误处理中间件,eg:app.use(err,req,res,next)第三方中间件,例如:bodyparser、cookieparser、路由器级中间件express.Router使用express.Router类创建模块化、可安装的路由处理。路由实例是一个完整的中间件和路由系统。您可以使用中间件进行日志记录、身份验证等。如下所示,记录用户的最新活动并解析身份验证标头,使用它来确定当前登录的用户并将其添加到Request对象。程序每次收到请求时都会执行此函数。如果有错误,它只是简单地结束响应,而不调用后续的中间件或路由处理。varrouter=express.Router()使用router.use()和router.METHOD()函数加载路由器级中间件。下面的示例创建一个路由器作为模块,在其中加载一个中间件函数,定义一些路由,并将路由器模块安装在主应用程序的路径上。varexpress=require('express');varrouter=express.Router();//一个没有安装路径的中间件函数。对路由器的每个请求都会执行此代码//loggingasyncfunctionlogMiddleware(req,res,next){下一个();}catch(){res.status(500).send(error.message);}}//身份验证异步函数checkAuthentication(req,res,next)=>{//检查标头或url参数或post参数以获取tokenconsttoken=req.body.token||请求查询令牌||req.headers['x-access-token']||req.headers['授权'];if(token){try{//验证秘密req.decoded=awaitjwt.verify(token,config.secret)让checkUser=awaitauthenticateTokenHelper.getUserDetail(req);//如果一切正常,保存到request以供其他路由使用if(checkUser){req.user=req.解码next()}else{returnres.status(403).json({message:responseMessage.noAuthorized})}}catch(err){returnres.status(401).json({message:responseMessage.invalidToken})}}else{//如果没有令牌返回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)。您必须通过提供四个参数将其标识为错误处理中间件函数。即使你不需要使用下一个对象,你也必须指定它。否则下一个对象将被解释为常规中间件并且将无法处理错误。基本签名如下所示:app.use(function(err,req,res,next){console.error(err.stack)res.status(500).send('Somethingbroke!')})示例1:app.get('/users',(req,res,next)=>{next(newError('我传递给你一个错误!'));});app.use((err,req,res,next)=>{console.log(err);if(!res.headersSent){res.status(500).send(err.message);}});在这种情况下,管道末端的错误处理中间件将处理错误。您可能还会注意到我检查了res.headersSent属性。这只是检查响应是否有发送给客户端的标头。如果还没有,它将向客户端发送HTTP500状态和错误消息。示例2:您还可以链接错误处理中间件。不同类型的错误通常有不同的处理方式:app.get('/users,(req,res,next)=>{leterr=newError('Icould\n'tfindit.');err.httpStatusCode=404;next(err);});app.get('/user,(req,res,next)=>{leterr=newError('对不起,戴夫,你不能那样做。');err.httpStatusCode=304;next(err);});app.use((err,req,res,next)=>{//处理未发现的错误if(err.httpStatusCode===404){res.status(400).render('NotFound');}//处理未经授权的错误elseif(err.httpStatusCode===304){res.status(304).render('Unauthorized');}//catch所有其他if(!res.headersSent){res.status(err.httpStatusCode||500).render('UnknownError');}next(err);});在这种情况下,中间件会检查是否抛出了404(未找到)错误。如果是,它会呈现“NotFound”模板页面,然后将错误传递给中间件中的下一个项目。下一个中间件检查是否抛出了304(未授权)错误。如果是,它将呈现“未授权”页面并将错误传递给管道中的下一个中间件。最后,“catchall”错误处理只记录错误,如果没有发送响应,它会发送错误的httpStatusCode(如果未提供,则发送HTTP500状态)并呈现“UnknownError”模板。第三方级中间件在某些情况下,我们会向后端添加一些额外的功能。首先安装Node.js模块以获得您需要的功能,然后在应用程序级别或路由器级别将其加载到您的应用程序中。示例:当body-parser处理Content-Type请求标头时,所有中间件将使用解析后的文字填充req.body属性。constexpress=require('express');constbodyParser=require('body-parser');constapp=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('serverrunningonport')})总结中间件功能是一种非常好的方式,可以在每个请求或针对特定路由的每个请求上运行代码,并根据请求或采取行动响应数据。中间件是现代Web服务器的重要组成部分,它非常有用。
