已经完成了Express4.x API中的Requst和Response对象的文档翻译。简单的总结,request对象即表示HTTP请求,包含了请求查询字符串,参数,内容,HTTP头等属性;response对象则表示HTTP响应,即在受到请求时向客户端发送的HTTP响应数据。Express则基于此提供给咱们一些方法,完成指定的请求和响应。html
技术库更迭较快,很难使译文和官方的API保持同步,咱们只有提高本身的英语能力才能更快的适应库的更新迭代,阅读到最新资料。
因此我这次翻译的目的,一是熟悉express文档,二是锻炼本身英语阅读能力;正则表达式
原文地址:express.comexpress
router
对象是中间件和路由的隔离实例,你能够把它看作一个仅能执行中间件和路由功能的mini-applaction
,每个Express应用程序实例都有一个内置的路由器json
路由器的行为相似于中间件自己,因此你能够把他做为一个参数传递给app.use()
或者做为参数传递给另外一个路由器的use()
方法。Express top-level
对象有一个Router()建立一个新的路由器对象api
建立一个新的路由器对象数组
var router = express.Router([options]);
可选择的options参数指定路由器的行为app
Property | Description | Default |
---|---|---|
caseSensitive | 是否启用大小写敏感 | 默认状况下不敏感,以相同的方式对待"/Foo","/foo" |
mergeParams | 从父路由器保存req.params 值,若是子父有冲突的参数名称,以子路由参数优先 |
false |
strict | 启用严格路由 | 默认状况下是禁用的,"/foo"和"/foo/"是相同的 |
你能够像应用程序那样添加中间件和HTTP方法路由(例如get,put,post等等)函数
// 调用传递给次路由的任何请求 router.use(function(req,res,next){ // 一些逻辑,和其余中间件同样 next(); }) // 将会处理任何以/events结束的请求 router.get('/events',function(req,res,next){ // .. })
而后你能够为你特定的URL使用路由器,用这种方式把你的routes分为文件甚至是mini-apps
post
app.use('/calendar',router);
这个方法就像router.METHHOD()
,除了他匹配全部的HTTP方法学习
这个方法对于映射特定路径前缀或任意匹配的"全局"逻辑很是有用。举个栗子,若是你将如下路由置于全部路由的最前面,它要求从该点的全部路由都须要身份认证,并自动加载user。记住这些回调函数没必要做为终点,loadUser
能够执行任务,而后经过next()
传递继续匹配给后续的路由
router.all('*',requireAuthentication,loadUser);
等价于
router.all('*',requireAuthentication) router.all('*',loadUser)
另外一个例子是white-listed
"global"功能,这里的例子很是的类似,可是它只限制路径的前缀"/api"
router.all('/api/*',requireAuthentication);
router.METHOD()
方法在Express中提供路由功能,其中METHOD是HTTP方法之一,例如GET,POST,PUT等等,固然你能够小写。因此实际的方法是router.get()
,router.post()
,router.put()
等等
router.get()
函数将会自动的调用HTTP HEAD方法,除了router.head()
在router.get()
以前要求没有走这条路
你能够提供多个回调,每一个回调都被平等对待,表现的就像中间件,除了这些回调函数能够调用next(route)
绕过其他路由回调。您可使用此机制在路由上执行预条件,而后在没有理由继续匹配路由的状况下将控制传递给后续路由。
下面片断展现了最简单的路由定义,Express将字符串转化为正则表达式,在内部用于匹配传入请求。执行这些匹配时不考虑查询字符串,例如'GET'将匹配下面路由,像GET/?name='tobi'
router.get('/',function(req,res){ res.send('hello world') })
若是你有很是具体的约束条件,还可使用正则表达式。举个栗子下面将会匹配"GET /commits/71dbb9c"以及 "GET /commits/71dbb9c..4c084f9".
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/,function(req,res){ var from = req.params[0]; var to = req.params[1] || 'HEAD'; res.send('commit range' + form + '..' + to); })
添加回调触发到路由参数中,name是参数的名称,callback是回调函数。虽然name在技术上是可选的,可是从Express v4.11.0没有它是不推荐使用这种方法的(以下)
不像
app.param()
,router.param()
不接受数组参数
举个栗子,当:user
在路由路径中存在时,能够将用户加载映射为自动提供req.user
给这个路由,或者执行验证的参数输入
router.param('user',function(req,res,next,id){ //尝试从用户模型获取用户详细信息并将其附加到请求对象 User.find(id,function(err,user){ if(err){ next(err); }else if(user){ req.user = user; next(); }else{ next(new Error('fail to load user')) } }) })
该回调方法是在本地路由器上定义他们,它们不是由加载的应用程序或路由器继承的。所以,定义在路由上的参数回调只有经过router
定义的路由参数才会触发
一个回调参数将被称为一次请求响应周期,即便参数在多个路径中匹配,以下面的栗子所示:
router.param('id',function(req,res,next,id){ console.log('CALLED ONLY ONCE'); next(); }) router.get('/user/:id',function(req,res,next){ console.log('although this matchs '); next(); }) router.get('/user/:id',function(req,res){ console.log('and this matchs too '); res.end(); })
将会依次打印:
CAALED ONLY ONCE although this matchs and this matchs too
如下部分描述
router.param(callback)
在v4.11.0将是过期的
router.param(name,callback)
方法的行为经过仅传递一个函数到router.param()
将会彻底改变。此功能是如何实现router.param(name,callback)
的习惯-它接受两个参数,必须返回一个中间件
函数返回的中间件决定了URL参数被捕获时发生的行为
在下面这个例子中,router.param(name,callback)
签名被修改成router.param(name, accessId)
。router.param()将会接受一个
name和一个
number而不是一个
name和一个
回调函数`
var express = require('express'); var app = express(); var router = express.Router(); // 定制 `router.param()`的功能 router.param(function(param,option){ return function(req,res,next,val){ if(val == option){ next(); }else{ res.sendStatus(403); } } }) // 使用定制的`router.param()` router.param('id',1337); // 触发捕获的路由 router.get('/user/:id',function(req,res){ res.send('OK') }) app.use(router); app.listen(3000,function(){ console.log('Ready'); })
在这个栗子中,router.param(name,callback)
签名是相同的,但不是一个中间件回调,一个自定义检查函数定义了验证用户ID
router.param(function(param,validator){ return function(req,res,next,val){ if(validator(val)){ next(); }else{ res.sendStatus(403) } } }) router.param('id',function(candidate){ return !isNaN(parseFloat(candidate)) && isFinite(candidate) })
返回单个路由的实例,您可使用可选中间件来处理HTTP verbs,使用router.route()
为了不重复路由命名,从而键入错误。
在上面router.param()
栗子的基础上,下面的栗子展现了如何使用router.route()
指定HTTP处理方法
var router = express.Router(); router.param('user_id',function(req,res,next,id){ // 示例用户,可能实际将从db等获取 req.user = { id:id, name:'TJ' }; next(); }) router.route('/users/:user_id') .all(function(req,res,next){ // .. next() }) .get(function(req,res,next){ res.json(req.user) }) .put(function(req,res){ req.user.name = req.params.name; // 保存用户等 res.json(req.user) }) .post(function(req,res,next){ next(new Error('not implemented')); }) .delete(function(req,res,next){ next(new Error('not implemented')) });
这个方法再利用单一/users/:user_id
路径而且为各类HTTP方法添加处理程序
使用指定中间件函数或者函数,可选的参数是挂载路径,默认是"/"
这个方法相似于app.use()
。下面展现了一个简单的示例和用例:
中间件就像是管道,请求在第一个中间件函数定义时开始,并为它们"向下"匹配每一条路径处理中间件堆栈处理。
var express = require('express'); var app = express(); var router = express.Router(); router.use(function(req,res){ console.log('%s %s %s',req.method,req.url,req.path); next(); }) // 下面只有当路径从挂载点开始时,才会调用这个函数 router.use('/bar',function(req,res,next){ // .. next(); }) // 老是调用 router.use(function(req,res,next){ res.send('Hello world') }); app.use('/foo',router); app.listen(3000);
“挂载”路径被剥离而且对中间件功能不可见。这个功能的主要做用是:无论它的"prefix前缀"路径,安装中间件功能可能没有代码的变化
为了保证您使用router.use()
定义的中间件的重要性。他们按顺序调用,所以顺序定义中间件优先级。举个栗子:一般logger
是您将使用的第一个中间件,所以每一个请求都会被记录
var logger = require('morgan'); router.user(logger()); router.use(express.static(__dirname+'/public')); router.use(function(req,res){ res.send('hello') })
如今假设您忽略了对静态文件的日志请求,可是在logger()
以后要继续记录路由和中间件定义。你只需简单的移动express.static()
到顶部,在添加日志中间件以前便可。
router.use(express.static(__dirname + '/public')); router.use(logger()); router.use(function(req,res){ res.send('Hello') })
另外一个例子是从多个目录中服务文件,给予"/public"优先
app.use(express.static(__dirname + '/public')); app.use(express.static(__dirname + '/files')); app.use(express.static(__dirname + '/uploads'));
router.use()
方法也支持命名参数,这样,其余路由器的挂载点能够经过使用命名参数预加载来获益。
NOTE:虽然这些中间件功能是经过特定路由器添加的,当他们运行时由他们链接到的路径来定义(而不是路由)。所以,若是路由器的路由匹配,则经过一个路由器添加的中间件能够运行其余路由器。举个栗子,下面显示安装在同一路径上的两个不一样的路由器:
var autoRouter = express.Router(); var openRouter = express.Router(); autoRouter.use(require('./authenticate').basic(usersdb)); autoRouter.get('/:user_id/edit',function(req,res,next){ // .. 编辑用户界面 .. }) openRouter.get('/',function(req,res,next){ // .. 用户列表 .. }) openRouter.get('/:user_id',function(req,res,next){ // .. 查看用户 .. }) app.use('/users',authRouter); app.use('/users',openRouter);
尽管authenticate
中间件是经过autoRouter
路由加入的,可是它也将运行在openRouter定义的路由上,由于两个路由器都挂载在/users
。为了不这种行为发生,为每一个路由器使用不一样的路径。
Express文档中Router部分就完成了,本人学识有限,不免有所纰漏或者理解不当之处,翻译仅仅是方便我的学习交流使用,无其余用意,原文地址:expressjs.com