express-13 中间件
简介
从概念上讲,中间件是一种功能的封装方式,具体来说就是封装在程序中处理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
请求头的支持,允许浏览器“假装”使用除GET
和POST
之外的HTTP
方法。这对调试有帮助。只在编写API时才需要。query: 解析查询字符串,并将其变成请求对象上的
query
属性。这个中间件是由Express隐含连入的,所以不要自己连入它。response-time: 向响应中添加
X-Response-Time
头,提供以毫秒为单位的响应时间。一般在做性能调优时才需要这个中间件。static: 提供对静态(public)文件的支持; 这个中间件可以连入多次,并可指定不同的目录。
vhost: 虚拟主机(vhost),这个术语是从Apache借来的,它可使子域名在Express中更容易管理。
express-13 中间件的更多相关文章
- Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API
A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...
- Express全系列教程之(五):Express的中间件
一.中间件 从字面意思,我们可以了解到它大概就是做中间代理操作,事实也是如此:大多数情况下,中间件就是在做接收到请求和发送响应中间的一系列操作.事实上,express是一个路由和中间件的web框架,E ...
- express之中间件bodyParser的理解
bodyParser用于解析客户端请求的body中的内容,内部使用JSON编码处理,url编码处理以及对于文件的上传处理.另外bodyParse也可以接受客户端ajax提交的json数据,以及url的 ...
- 单页面应用的History路由模式express后端中间件配合
这篇文章主要分享一下通过HTML5的history API的时候,使用NodeJS后端应该如何配置,来避免产生404的问题,这里是使用的express的框架,主要是通过connect-history- ...
- 77.深入理解nodejs中Express的中间件
转自:https://blog.csdn.net/huang100qi/article/details/80220012 Express是一个基于Node.js平台的web应用开发框架,在Node.j ...
- Nodejs 进阶:Express 常用中间件 body-parser 实现解析
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 写在前面 body-parser是非常常用的一个express中 ...
- [转] Nodejs 进阶:Express 常用中间件 body-parser 实现解析
写在前面 body-parser是非常常用的一个express中间件,作用是对post请求的请求体进行解析.使用非常简单,以下两行代码已经覆盖了大部分的使用场景. app.use(bodyParser ...
- 【nodejs】--express的中间件multer实现图片文件上传--【XUEBIG】
Multer是nodejs中处理multipart/form-data数据格式(主要用在上传功能中)的中间件.该中间件不处理multipart/form-data数据格式以外的任何形式的数据 Tips ...
- express有中间件的增删改查
var express = require('express');引入express框架 var router = express.Router();引入router路由级中间件 var data = ...
随机推荐
- mybatis,批量新增、修改,删除
转载自:http://blog.csdn.net/sanyuesan0000/article/details/19998727 最近需要用到Mybatis批量新增oracle数据库,刚开始在网上找到的 ...
- 100个Github上Android开源库
项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, ...
- 【leetcode】Best Time to Buy and Sell (easy)
题目: Say you have an array for which the ith element is the price of a given stock on day i. If you w ...
- 什么是ORACLEASM
最直观的用途:共享一块磁盘,各个服务器做oracleasm即可共享 一. ASM(自动存储管理)的来由: ASM是Oracle 10g R2中为了简化Oracle数据库的管理而推出来的一项新功 ...
- yii压缩
application\components\controller.php protected function afterRender($view, &$output) { if(Yii:: ...
- 解决sqlite3_key的问题
报错内容显示如下: ld: warning: ignoring file /Users/rowling/Library/Developer/Xcode/DerivedData/zhinengbango ...
- swift选择类或结构体
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体: 结构体的主要目的是用来封装少量相关简单数据值. 有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用. ? 任何在结 ...
- "".equals(str)和str.equals("")的区别
如果当str为null的话 "".equals(str)不会报空指针异常,而str.equals("")会报异常.这种方式主要用来防止空指针异常
- Sample Apps by Android Team -- Amazed
Sample Apps by Android Team 代码下载:http://pan.baidu.com/s/1eSNmdUE , 代码原地址:https://code.google.com/arc ...
- poj 1003:Hangover(水题,数学模拟)
Hangover Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 99450 Accepted: 48213 Descri ...