简介

  • 从概念上讲,中间件是一种功能的封装方式,具体来说就是封装在程序中处理HTTP请求的功能。

  • 中间件是在管道中执行的,在Express程序中,通过调用app.use向管道中插入中间件。(在Express 4.0中,中间件和路由处理器是按它们的连入顺序调用的)

  • 在管道的最后放一个“捕获一切”请求的处理器是常见的做法,由它来处理跟前面其他所有路由都不匹配的请求。这个中间件一般会返回状态码404(未找到)。

  • 如果不调用next(),请求就在那个中间件中终止了。

中间件和路由处理器

  • 路由处理器(app.get、app.post等,经常被统称为app.VERB)可以被看作只处理特定HTTP谓词(GET、POST等)的中间件; 也可以将中间件看作可以处理全部HTTP谓词的路由处理器(基本上等同于app.all,可以处理任何HTTP谓词;

  • 路由处理器的第一个参数必须是路径;中间件也可以将路径作为第一个参数,但它是可选的(如果忽略这个参数,它会匹配所有路径)。

  • 路由处理器和中间件的参数中都有回调函数,这个函数有2个、3个或4个参数;

    • 如果有2个或3个参数,头两个参数是请求和响应对象,第三个参数是next函数。
    • 如果有4个参数,它就变成了错误处理中间件,第一个参数变成了错误对象,然后依次是请求、响应和next对象。
  • 如果不调用next(),管道就会被终止,也不会再有处理器或中间件做后续处理。

    • 如果不调用next(),则应该发送一个响应到客户端(res.send、res.json、res.render等);
    • 如果不这样做,客户端会被挂起并最终导致超时。
  • 如果调用了next(),一般不宜再发送响应到客户端。

    • 如果发送了,管道中后续的中间件或路由处理器还会执行,但它们发送的任何响应都会被忽略。
app.use(function(req, res, next){
console.log('processing request for "' + req.url + '"....');
next();
}); app.use(function(req, res, next){
console.log('terminating request');
res.send('thanks for playing!');
// 注意,我们没有调用next()......这样请求处理就终止了;
//如果忽略了`res.send`,则不会有响应返回到客户端,最终会导致客户端超时。
}); //最后一个中间件永远也不会执行
app.use(function(req, res, next){
console.log('whoops, i\'ll never get called!');
});
var app = require('express')();

app.use(function(req, res, next){
console.log('\n\nALLWAYS');
next();
}); app.get('/a', function(req, res){
console.log('/a: 路由终止');
res.send('a');
});
app.get('/a', function(req, res){
console.log('/a: 永远不会调用');
});
app.get('/b', function(req, res, next){
console.log('/b: 路由未终止');
next();
});
app.use(function(req, res, next){
console.log('SOMETIMES');
next();
});
app.get('/b', function(req, res, next){
console.log('/b (part 2): 抛出错误' );
throw new Error('b 失败');
}); app.use('/b', function(err, req, res, next){
console.log('/b 检测到错误并传递');
next(err);
});
app.get('/c', function(err, req){
console.log('/c: 抛出错误');
throw new Error('c 失败');
});
app.use('/c', function(err, req, res, next){
console.log('/c: 检测到错误但不传递');
next();
}); app.use(function(err, req, res, next){
console.log('检测到未处理的错误: ' + err.message);
res.send('500 - 服务器错误');
}); app.use(function(req, res){
console.log('未处理的路由');
res.send('404 - 未找到');
}); app.listen(3000, function(){
console.log('监听端口3000');
});

要特别注意请求/b和请求/c的差异,在这两个实例中都有一个错误,但一个结果是404,另一个是500。

  • 中间件必须是一个函数

  • 模块可以输出一个函数,而这个函数又可以直接用作中间件。

//lib/tourRequiresWaiver.js模块
module.exports = function(req,res,next){
var cart = req.session.cart;
if(!cart) return next();
if(cart.some(function(item){ return item.product.requiresWaiver; })){
if(!cart.warnings) cart.warnings = [];
cart.warnings.push('One or more of your selected tours' +
'requires a waiver.');
}
next();
} //引入这个中间件:
app.use(require('./lib/requiresWaiver.js')); //不过更常见的做法是输出一个以中间件为属性的对象
module.exports = {
checkWaivers: function(req, res, next){
var cart = req.session.cart;
if(!cart) return next();
if(cart.some(function(i){ return i.product.requiresWaiver; })){
if(!cart.warnings) cart.warnings = [];
cart.warnings.push('One or more of your selected ' +
'tours requires a waiver.');
}
next();
}, checkGuestCounts: function(req, res, next){
var cart = req.session.cart;
if(!cart) return next();
if(cart.some(function(item){ return item.guests >
item.product.maximumGuests; })){
if(!cart.errors) cart.errors = [];
cart.errors.push('One or more of your selected tours ' +
'cannot accommodate the number of guests you ' +
'have selected.');
}
next();
}
} //像以下这样连入中间件 var cartValidation = require('./lib/cartValidation.js'); app.use(cartValidation.checkWaivers);
app.use(cartValidation.checkGuestCounts);

在前面的例子中,我们的中间件会用语句return next()提前终止。Express不期望中间件返回值(并且它不会用返回值做任何事情),所以这只是缩短了的next(); return;。

常用中间件

Express 4.0之后,唯一保留在Express中的中间件只剩下static

  • basicAuth: 提供基本的访问授权。basic-auth只提供最基本的安全,并且只能通过HTTPS使用basic-auth(否则用户名和密码是通过明文传输的)。只有在需要又快又容易的东西,并且在使用HTTPS时,才应该用basic-auth。

  • body-parser: 只连入json和urlencoded的便利中间件。

  • json: 解析JSON编码的请求体。

  • urlencoded: 解析互联网媒体类型为application/x-www-form-urlencoded的请求体。这是处理表单和AJAX请求最常用的方式;

  • multipart(已废弃): 解析互联网媒体类型为multipart/form-data的请求体; 应该用Busboy或Formidable代替它。

  • compress: 用gzip压缩响应数据。特别使用在那些网络比较慢或者用手机上网的情况; 它应该在任何可能会发送响应的中间件之前被尽早连入。唯一应该出现在compress之前的中间件只有debugging或logging(它们不发送响应)。

  • cookie-parser: 提供对cookie的支持; app.use(require(cookie-parser)(秘钥放在这里);

  • cookie-session: 提供cookie存储的会话支持。一般不推荐使用这种存储方式的会话;一定要把它放在cookie-parser后面连入。

  • express-session: 提供会话ID (存在cookie里)的会话支持。默认存在内存里,不适用于生产环境,并且可以配置为使用数据库存储。

  • csurf: 防范跨域请求伪造(CSRF)攻击。因为它要使用会话,所以必须放在express-session中间件后面。它目前等同于connect.csrf中间件。可惜简单连入这个中间件并不能神奇地防范CSRF攻击;

  • directory: 提供静态文件的目录清单支持。如果不需要目录清单,则无需引入这个中间件。

  • errorhandler: 为客户端提供栈追踪和错误消息;建议不要在生产环境中连入它,因为它会暴露实现细节,可能引发安全或隐私问题。

  • static-favicon: 提供favicon(出现在浏览器标题栏上的图标)。这个中间件不是必需的,可以简单地在static目录下放一个favicon.ico,但这个中间件能提升性能。如果要使用它,应该尽可能地往中间件栈的上面放。

  • morgan: 提供自动日志记录支持:所有请求都会被记录。

  • method-override: 提供对x-http-method-override请求头的支持,允许浏览器“假装”使用除GETPOST之外的HTTP方法。这对调试有帮助。只在编写API时才需要。

  • query: 解析查询字符串,并将其变成请求对象上的query属性。这个中间件是由Express隐含连入的,所以不要自己连入它。

  • response-time: 向响应中添加X-Response-Time头,提供以毫秒为单位的响应时间。一般在做性能调优时才需要这个中间件。

  • static: 提供对静态(public)文件的支持; 这个中间件可以连入多次,并可指定不同的目录。

  • vhost: 虚拟主机(vhost),这个术语是从Apache借来的,它可使子域名在Express中更容易管理。

express-13 中间件的更多相关文章

  1. Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API

    A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...

  2. Express全系列教程之(五):Express的中间件

    一.中间件 从字面意思,我们可以了解到它大概就是做中间代理操作,事实也是如此:大多数情况下,中间件就是在做接收到请求和发送响应中间的一系列操作.事实上,express是一个路由和中间件的web框架,E ...

  3. express之中间件bodyParser的理解

    bodyParser用于解析客户端请求的body中的内容,内部使用JSON编码处理,url编码处理以及对于文件的上传处理.另外bodyParse也可以接受客户端ajax提交的json数据,以及url的 ...

  4. 单页面应用的History路由模式express后端中间件配合

    这篇文章主要分享一下通过HTML5的history API的时候,使用NodeJS后端应该如何配置,来避免产生404的问题,这里是使用的express的框架,主要是通过connect-history- ...

  5. 77.深入理解nodejs中Express的中间件

    转自:https://blog.csdn.net/huang100qi/article/details/80220012 Express是一个基于Node.js平台的web应用开发框架,在Node.j ...

  6. Nodejs 进阶:Express 常用中间件 body-parser 实现解析

    本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 写在前面 body-parser是非常常用的一个express中 ...

  7. [转] Nodejs 进阶:Express 常用中间件 body-parser 实现解析

    写在前面 body-parser是非常常用的一个express中间件,作用是对post请求的请求体进行解析.使用非常简单,以下两行代码已经覆盖了大部分的使用场景. app.use(bodyParser ...

  8. 【nodejs】--express的中间件multer实现图片文件上传--【XUEBIG】

    Multer是nodejs中处理multipart/form-data数据格式(主要用在上传功能中)的中间件.该中间件不处理multipart/form-data数据格式以外的任何形式的数据 Tips ...

  9. express有中间件的增删改查

    var express = require('express');引入express框架 var router = express.Router();引入router路由级中间件 var data = ...

随机推荐

  1. 解决X64操作系统PL/SQL连接报错问题 make sure you have the 32 bits oracle client installed

    Windows 64位下装Oracle 11g 64位,PLSQL Developer使用出现以下问题: 1.Database下拉框为空: 2.强制输入用户名.密码及Database,登录弹出: In ...

  2. NIS 报错No such map passwd.byname. Reason: Can't bind to server which serves this domain

    在NIS—client端使用命令:ypcat passwd ,把错如上题, 原因:client端ypbind服务未启动解决方法:当然是启动ypbind了,命令:service ypbind start ...

  3. Android Studio新建了一个项目看不到手机界面的效果

    我今天新建了一个项目,但是在这里却看不到手机的界面效果,如下图:

  4. python基础——map/reduce

    python基础——map/reduce Python内建了map()和reduce()函数. 如果你读过Google的那篇大名鼎鼎的论文“MapReduce: Simplified Data Pro ...

  5. 四、优化及调试--网站优化--Yahoo军规上

    什么是Yahoo军规?即如何提高网站速度的知识. 具体如下: 1.尽量减少HTTP请求个数——须权衡 什么是http请求:从客户端到服务器端的请求消息.包括消息首行中,对资源的请求方法,资源的标识符及 ...

  6. IT人学习方法论(一):学习方向

    07年的时候曾经讲过一节Webcast,名叫<使您成为Windows专家的一些学习习惯 >.直到最近,还经常收到听众关于这一节课反馈和心得的电子邮件,可见学习方法论是大家非常关心的问题.因 ...

  7. smarty汇总

    Smarty:模板技术 实现功能:前后分离. 原理:主要通过Smarty核心类实现,调用display方法,将模板文件读取,用正则进行替换,替换完保存到临时文 件,将临时文件加载到当前页面. 配置文件 ...

  8. Java -- 找不到或无法加载主类

    原文:http://wenku.baidu.com/link?url=5nS1GEaePn-hmtAg6xXdJvtt9Z89JQsakhqSv8fambaJY2t9nKPtf3hXFpjW-BtD9 ...

  9. xdg-open filename 以相应的程序 打开文件

    [root@ok network-scripts]# xdg-open ifcfg-eth0

  10. 使用Modernizr探测HTML5/CSS3新特性(转载)

    转载地址:http://www.cnblogs.com/TomXu/archive/2011/11/18/detecting-html5-css3-features-using-modernizr.h ...