├── README.md
└── Express_4.x_API_Chinese.md
/README.md:
--------------------------------------------------------------------------------
1 | # express_api_4.x_chinese
2 |
3 |
4 |
5 | express 4.x api 中文手册
6 | online doc:https://www.zybuluo.com/XiangZhou/note/208532
7 |
--------------------------------------------------------------------------------
/Express_4.x_API_Chinese.md:
--------------------------------------------------------------------------------
1 | # Express 4.x API
2 |
3 | 标签(空格分隔): express 翻译 api文档 中文
4 |
5 | ---
6 |
7 | ##express()
8 |
9 | `express()`用来创建一个Express的程序。`express()`方法是***express***模块导出的顶层方法。
10 | ```js
11 | var express = require('express');
12 | var app = express();
13 | ```
14 |
15 | ###Methods
16 | ####express.static(root, [options])
17 | `express.static`是Express中唯一的内建中间件。它以[server-static][1]模块为基础开发,负责托管 Express 应用内的静态资源。
18 | 参数`root`为静态资源的所在的根目录。
19 | 参数`options`是可选的,支持以下的属性:
20 | |属性|描述|类型|默认值|
21 | |:----:|:----:|:----:|:------:|
22 | |dotfiles|是否响应点文件。供选择的值有"allow","deny"和"ignore"|String|"ignore"|
23 | |etag|使能或者关闭etag|Boolean|true|
24 | |extensions|设置文件延期回退|Boolean|true|
25 | |index|发送目录索引文件。设置false将不发送。|Mixed|"index.html"|
26 | |lastModified|设置文件在系统中的最后修改时间到`Last-Modified`头部。可能的取值有`false`和`true`。|Boolean|true|
27 | |maxAge|在Cache-Control头部中设置`max-age`属性,精度为毫秒(ms)或则一段[ms format][2]的字符串|Number|0|
28 | |redirect|当请求的pathname是一个目录的时候,重定向到尾随"/"|Boolean|true|
29 | |setHeaders|当响应静态文件请求时设置headers的方法|Funtion||
30 |
31 | 如果你想获得更多关于使用中间件的细节,你可以查阅[Serving static files in Express][3]。
32 |
33 | ##Application()
34 | `app`对象一般用来表示Express程序。通过调用Express模块导出的顶层的`express()`方法来创建它:
35 | ```js
36 | var express = require('express');
37 | var app = express();
38 |
39 | app.get('/', function(req, res) {
40 | res.send('hello world!');
41 | });
42 |
43 | app.listen(3000);
44 | ```
45 | `app`对象具有以下的方法:
46 |
47 | - 路由HTTP请求;具体可以看[app.METHOD][4]和[app.param][5]这两个例子。
48 | - 配置中间件;具体请看[app.route][6]。
49 | - 渲染HTML视图;具体请看[app.render][7]。
50 | - 注册模板引擎;具体请看[app.engine][8]。
51 |
52 | 它还有一些属性设置,这些属性可以改变程序的行为。获得更多的信息,可以查阅[Application settings][9]。
53 |
54 | ###Properties
55 | ####app.locals
56 | `app.locals`对象是一个javascript对象,它的属性就是程序本地的变量。
57 | ```js
58 | app.locals.title
59 | // => 'My App'
60 |
61 | app.locals.email
62 | // => 'me@myapp.com'
63 | ```
64 | 一旦设定,`app.locals`的各属性值将贯穿程序的整个生命周期,与其相反的是`res.locals`,它只在这次请求的生命周期中有效。
65 |
66 | 在程序中,你可以在渲染模板时使用这些本地变量。它们是非常有用的,可以为模板提供一些有用的方法,以及`app`级别的数据。通过`req.app.locals`(具体查看[req.app][10]),Locals可以在中间件中使用。
67 | ```js
68 | app.locals.title = 'My App';
69 | app.locals.strftime = require('strftime');
70 | app.locals.email = 'me@myapp.com';
71 | ```
72 |
73 | ####app.mountpath
74 | `app.mountpath`属性是子程序挂载的路径模式。
75 | >一个子程序是一个`express`的实例,其可以被用来作为路由句柄来处理请求。
76 | >
77 | ```js
78 | var express = require('express');
79 | var app = express(); // the main app
80 | var admin = express(); // the sub app
81 | admin.get('/', function(req, res) {
82 | console.log(admin.mountpath); // /admin
83 | res.send('Admin Homepage');
84 | });
85 |
86 | app.use('/admin', admin); // mount the sub app
87 | ```
88 | 它和req对象的[baseUrl][11]属性比较相似,除了`req.baseUrl`是匹配的URL路径,而不是匹配的模式。如果一个子程序被挂载在多条路径模式,`app.mountpath`就是一个关于挂载路径模式项的列表,如下面例子所示。
89 | ```js
90 | var admin = express();
91 | admin.get('/', function(req, res) {
92 | console.log(admin.mountpath); // ['adm*n', '/manager']
93 | res.send('Admin Homepage');
94 | });
95 |
96 | var secret = express();
97 | secret.get('/', function(req, res) {
98 | console.log(secret.mountpath); // /secr*t
99 | res.send('Admin secret');
100 | });
101 |
102 | admin.use('secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
103 | app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager' , on the parent app
104 |
105 | ```
106 |
107 | ###Events
108 | ####app.on('mount', callback(parent))
109 | 当子程序被挂载到父程序时,`mount`事件被发射。父程序对象作为参数,传递给回调方法。
110 | ```js
111 | var admin = express();
112 | admin.on('mount', function(parent) {
113 | console.log('Admin Mounted');
114 | console.log(parent); // refers to the parent app
115 | });
116 |
117 | admin.get('/', function(req, res) {
118 | res.send('Admin Homepage');
119 | });
120 |
121 | app.use('/admin', admin);
122 |
123 | ```
124 |
125 | ###Methods
126 | ####app.all(path, callback[, callback ...]
127 | `app.all`方法和标准的`app.METHOD()`方法相似,除了它匹配所有的HTTP动词。
128 | 对于给一个特殊前缀映射一个全局的逻辑处理,或者无条件匹配,它是很有效的。例如,如果你把下面内容放在所有其他的路由定义的前面,它要求所有从这个点开始的路由需要认证和自动加载一个用户。记住这些回调并不是一定是终点:`loadUser`可以在完成了一个任务后,调用`next()`方法来继续匹配随后的路由。
129 | ```js
130 | app.all('*', requireAuthentication, loadUser);
131 | ```
132 | 或者这种相等的形式:
133 | ```js
134 | app.all('*', requireAuthentication);
135 | app.all('*', loadUser);
136 | ```
137 | 另一个例子是全局的白名单方法。这个例子和前面的很像,然而它只是限制以`/api`开头的路径。
138 | ```js
139 | app.all('/api/*', requireAuthentication);
140 | ```
141 |
142 | ####app.delete(path, callback[, callback ...])
143 | 路由`HTTP DELETE`请求到有特殊回调方法的特殊的路径。获取更多的信息,可以查阅[routing guide][12]。
144 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果不能满足当前路由的处理条件,那么你可以传递控制到随后的路由。
145 | ```js
146 | app.delete('/', function(req, res) {
147 | res.send('DELETE request to homepage');
148 | });
149 | ```
150 |
151 | ####app.disable(name)
152 | 设置类型为布尔的设置名为`name`的值为`false`,此处的`name`是[app settings table][13]中各属性的一个。调用`app.set('foo', false)`和调用`app.disable('foo')`是等价的。
153 | 比如:
154 | ```js
155 | app.disable('trust proxy');
156 | app.get('trust proxy');
157 | // => false
158 | ```
159 | ####app.disabled(name)
160 | 返回`true`如果布尔类型的设置值`name`被禁用为`false`,此处的`name`是[app settings table][14]中各属性的一个。
161 | ```js
162 | app.disabled('trust proxy');
163 | // => true
164 | app.enable('trust proxy');
165 | app.disabled('trust proxy');
166 | // => false
167 | ```
168 |
169 | ####app.enable(name)
170 | 设置布尔类型的设置值`name`为`true`,此处的`name`是[app settings table][15]中各属性的一个。调用`app.set('foo', true)`和调用`app.enable('foo')`是等价的。
171 | ```js
172 | app.enable('trust proxy');
173 | app.get('trust proxy');
174 | // => true
175 | ```
176 | ####app.enabled(name)
177 | 返回`true`如果布尔类型的设置值`name`被启动为`true`,此处的`name`是[app settings table][16]中各属性的一个。
178 | ```js
179 | app.enabled('trust proxy');
180 | // => false
181 | app.enable('trust proxy');
182 | app.enabled('trust proxy');
183 | // => true
184 | ```
185 |
186 | ####app.engine(ext, callback)
187 | 注册给定引擎的回调,用来渲染处理ext文件。
188 | 默认情况下,Express需要使用`require()`来加载基于文件扩展的引擎。例如,如果你尝试渲染一个`foo.jade`文件,Express在内部调用下面的内容,同时缓存`require()`结果供随后的调用,来加速性能。
189 | ```js
190 | app.engine('jade', require('jade').__express);
191 | ```
192 | 使用下面的方法对于那些没有提供开箱即用的`.__express`方法的模板,或者你希望使用不同的模板引擎扩展。
193 | 比如,使用EJS模板引擎来渲染`.html`文件:
194 | ```js
195 | app.engine('html', require('ejs').renderFile);
196 | ```
197 | 在这个例子中,EJS提供了一个`.renderFile`方法,这个方法满足了Express规定的签名规则:`(path, options, callback)`,然而记住在内部它只是`ejs.__express`的一个别名,所以你可以在不做任何事的情况下直接使用`.ejs`扩展。
198 | 一些模板引擎没有遵循这种规范,[consolidate.js][17]库映射模板引擎以下面的使用方式,所以他们可以无缝的和Express工作。
199 | ```js
200 | var engines = require('consolidate');
201 | app.engine('haml', engines.haml);
202 | app.engine('html', engines.hogan);
203 | ```
204 | ####app.get(name)
205 | 获得设置名为`name`的app设置的值,此处的`name`是[app settings table][18]中各属性的一个。
206 | 如下:
207 | ```js
208 | app.get('title');
209 | // => undefined
210 |
211 | app.set('title', 'My Site');
212 | app.get('title');
213 | // => 'My Site'
214 | ```
215 |
216 | ####app.get(path, callback [, callback ...])
217 | 路由`HTTP GET`请求到有特殊回调的特殊路径。获取更多的信息,可以查阅[routing guide][19]。
218 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果请求没能满足当前路由的处理条件,那么传递控制到随后的路由。
219 | ```js
220 | app.get('/', function(req, res) {
221 | res.send('GET request to homepage');
222 | });
223 | ```
224 |
225 | ####app.listen(port, [hostname], [backlog], [callback])
226 | 绑定程序监听端口到指定的主机和端口号。这个方法和`Node`中的[http.Server.listen()][20]是一样的。
227 | ```js
228 | var express = require('express');
229 | var app = express();
230 | app.listen(3000);
231 | ```
232 | 通过调用`express()`返回得到的`app`实际上是一个JavaScript的`Function`,被设计用来作为一个回调传递给`Node HTTP servers`来处理请求。这样,其就可以很简便的基于同一份代码提供http和https版本,所以app没有从这些继承(它只是一个简单的回调)。
233 | ```js
234 | var express = require('express');
235 | var https = require('https');
236 | var http = require('http');
237 |
238 | http.createServer(app).listen(80);
239 | https.createServer(options, app).listen(443);
240 | ```
241 | `app.listen()`方法是下面所示的一个便利的方法(只针对HTTP协议):
242 | ```js
243 | app.listen = function() {
244 | var server = http.createServer(this);
245 | return server.listen.apply(server, arguments);
246 | };
247 | ```
248 |
249 | ####app.METHOD(path, callback [, callback ...])
250 | 路由一个HTTP请求,`METHOD`是这个请求的HTTP方法,比如`GET`,`PUT`,`POST`等等,注意是小写的。所以,实际的方法是`app.get()`,`app.post()`,`app.put()`等等。下面有关于方法的完整的表。
251 | 获取更多信息,请看[routing guide][21]。
252 | Express支持下面的路由方法,对应与同名的HTTP方法:
253 |
254 |
255 |
256 |
257 |
258 |
259 | - checkout
260 | - connect
261 | - copy
262 | - delete
263 | - get
264 | - head
265 | - lock
266 | - merge
267 | - mkactivity
268 | |
270 |
271 |
272 | - mkcol
273 | - move
274 | - m-search
275 | - notify
276 | - options
277 | - patch
278 | - post
279 | - propfind
280 | - proppatch
281 | |
283 |
284 |
285 | - purege
286 | - put
287 | - report
288 | - search
289 | - subscribe
290 | - trace
291 | - unlock
292 | - unsubscribe
293 | |
295 |
296 |
297 |
298 |
299 | >如果使用上述方法时,导致了无效的javascript的变量名,可以使用中括号符号,比如,`app['m-search']('/', function ...`
300 |
301 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果请求没有满足当前路由的处理条件,那么传递控制到随后的路由。
302 |
303 | >本API文档把使用比较多的HTTP方法`app.get()`,`app.post`,`app.put()`,`app.delete()`作为一个个单独的项进行说明。然而,其他上述列出的方法以完全相同的方式工作。
304 |
305 | `app.all()`是一个特殊的路由方法,它不属于HTTP协议中的规定的方法。它为一个路径加载中间件,其对所有的请求方法都有效。
306 |
307 | ```js
308 | app.all('/secret', function (req, res) {
309 | console.log('Accessing the secret section...');
310 | next(); // pass control to the next handler
311 | });
312 | ```
313 |
314 | ####app.param([name], callback)
315 | 给路由参数添加回调触发器,这里的`name`是参数名或者参数数组,`function`是回调方法。回调方法的参数按序是请求对象,响应对象,下个中间件,参数值和参数名。
316 | 如果`name`是数组,会按照各个参数在数组中被声明的顺序将回调触发器注册下来。还有,对于除了最后一个参数的其他参数,在他们的回调中调用`next()`来调用下个声明参数的回调。对于最后一个参数,在回调中调用`next()`将调用位于当前处理路由中的下一个中间件,如果`name`只是一个`string`那就和它是一样的(就是说只有一个参数,那么就是最后一个参数,和数组中最后一个参数是一样的)。
317 | 例如,当`:user`出现在路由路径中,你可以映射用户加载的逻辑处理来自动提供`req.user`给这个路由,或者对输入的参数进行验证。
318 | ```js
319 | app.param('user', function(req, res, next, id) {
320 | User.find(id, function(error, user) {
321 | if (err) {
322 | next(err);
323 | }
324 | else if (user){
325 | req.user = user;
326 | } else {
327 | next(new Error('failed to load user'));
328 | }
329 | });
330 | });
331 | ```
332 | 对于`Param`的回调定义的路由来说,他们是局部的。它们不会被挂载的app或者路由继承。所以,定义在`app`上的`Param`回调只有是在`app`上的路由具有这个路由参数时才起作用。
333 | 在定义`param`的路由上,`param`回调都是第一个被调用的,它们在一个请求-响应循环中都会被调用一次并且只有一次,即使多个路由都匹配,如下面的例子:
334 | ```js
335 | app.param('id', function(req, res, next, id) {
336 | console.log('CALLED ONLY ONCE');
337 | next();
338 | });
339 |
340 | app.get('/user/:id', function(req, res, next) {
341 | console.log('although this matches');
342 | next();
343 | });
344 |
345 | app.get('/user/:id', function(req, res) {
346 | console.log('and this mathces too');
347 | res.end();
348 | });
349 | ```
350 | 当`GET /user/42`,得到下面的结果:
351 | ```log
352 | CALLED ONLY ONCE
353 | although this matches
354 | and this matches too
355 | ```
356 | ```js
357 | app.param(['id', 'page'], function(req, res, next, value) {
358 | console.log('CALLED ONLY ONCE with', value);
359 | next();
360 | });
361 |
362 | app.get('/user/:id/:page', function(req. res, next) {
363 | console.log('although this matches');
364 | next();
365 | });
366 |
367 | app.get('/user/:id/:page', function (req, res, next) {
368 | console.log('and this matches too');
369 | res.end();
370 | });
371 |
372 | ```
373 |
374 | 当执行`GET /user/42/3`,结果如下:
375 | ```log
376 | CALLED ONLY ONCE with 42
377 | CALLED ONLY ONCE with 3
378 | although this matches
379 | and this mathes too
380 | ```
381 | >下面章节描述的`app.param(callback)`在v4.11.0之后被弃用。
382 |
383 | 通过只传递一个回调参数给`app.param(name, callback)`方法,`app.param(naem, callback)`方法的行为将被完全改变。这个回调参数是关于`app.param(name, callback)`该具有怎样的行为的一个自定义方法,这个方法必须接受两个参数并且返回一个中间件。
384 | 这个回调的第一个参数就是需要捕获的url的参数名,第二个参数可以是任一的JavaScript对象,其可能在实现返回一个中间件时被使用。
385 | 这个回调方法返回的中间件决定了当URL中包含这个参数时所采取的行为。
386 | 在下面的例子中,`app.param(name, callback)`参数签名被修改成了`app.param(name, accessId)`。替换接受一个参数名和回调,`app.param()`现在接受一个参数名和一个数字。
387 | ```js
388 | var express = require('express');
389 | var app = express();
390 |
391 | app.param(function(param, option){
392 | return function(req, res, next, val) {
393 | if (val == option) {
394 | next();
395 | }
396 | else {
397 | res.sendStatus(403);
398 | }
399 | }
400 | });
401 |
402 | app.param('id', 1337);
403 |
404 | app.get('/user/:id', function(req, res) {
405 | res.send('Ok');
406 | });
407 |
408 | app.listen(3000, function() {
409 | console.log('Ready');
410 | });
411 | ```
412 | 在这个例子中,`app.param(name, callback)`参数签名保持和原来一样,但是替换成了一个中间件,定义了一个自定义的数据类型检测方法来检测`user id`的类型正确性。
413 | ```js
414 | app.param(function(param, validator) {
415 | return function(req, res, next, val) {
416 | if (validator(val)) {
417 | next();
418 | }
419 | else {
420 | res.sendStatus(403);
421 | }
422 | }
423 | });
424 |
425 | app.param('id', function(candidate) {
426 | return !isNaN(parseFloat(candidate)) && isFinite(candidate);
427 | });
428 | ```
429 | >在使用正则表达式来,不要使用`.`。例如,你不能使用`/user-.+/`来捕获`user-gami`,用使用`[\\s\\S]`或者`[\\w\\>W]`来代替(正如`/user-[\\s\\S]+/`)。
430 | >```js
431 | > //captures '1-a_6' but not '543-azser-sder'
432 | > router.get('/[0-9]+-[[\\w]]*', function);
433 |
434 | > //captures '1-a_6' and '543-az(ser"-sder' but not '5-a s'
435 | > router.get('/[0-9]+-[[\\S]]*', function);
436 |
437 | > //captures all (equivalent to '.*')
438 | > router.get('[[\\s\\S]]*', function);
439 | >```
440 |
441 | ####app.path()
442 | 通过这个方法可以得到`app`典型的路径,其是一个`string`。
443 | ```js
444 | var app = express()
445 | , blog = express()
446 | , blogAdmin = express();
447 |
448 | app.use('/blog', blog);
449 | app.use('/admin', blogAdmin);
450 |
451 | console.log(app.path()); // ''
452 | console.log(blog.path()); // '/blog'
453 | console.log(blogAdmin.path()); // '/blog/admin'
454 | ```
455 | 如果`app`挂载很复杂下,那么这个方法的行为也会很复杂:一种更好用的方式是使用`req.baseUrl`来获得这个app的典型路径。
456 |
457 | ####app.post(path, callback, [callback ...])
458 | 路由`HTTP POST`请求到有特殊回调的特殊路径。获取更多的信息,可以查阅[routing guide][22]。
459 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果请求没能满足当前路由的处理条件,那么传递控制到随后的路由。
460 | ```js
461 | app.post('/', function(req, res) {
462 | res.send('POST request to homepage')
463 | });
464 | ```
465 |
466 | ####app.put(path, callback, [callback ...])
467 | 路由`HTTP PUT`请求到有特殊回调的特殊路径。获取更多的信息,可以查阅[routing guide][23]。
468 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果请求没能满足当前路由的处理条件,那么传递控制到随后的路由。
469 | ```js
470 | app.put('/', function(req, res) {
471 | res.send('PUT request to homepage');
472 | });
473 | ```
474 |
475 | ####app.render(view, [locals], callback)
476 | 通过`callback`回调返回一个`view`渲染之后得到的HTML文本。它可以接受一个可选的参数,可选参数包含了这个`view`需要用到的本地数据。这个方法类似于`res.render()`,除了它不能把渲染得到的HTML文本发送给客户端。
477 | >将`app.render()`当作是可以生成渲染视图字符串的工具方法。在`res.render()`内部,就是使用的`app.render()`来渲染视图。
478 |
479 | >如果使能了视图缓存,那么本地变量缓存就会保留。如果你想在开发的过程中缓存视图,设置它为`true`。在生产环境中,视图缓存默认是打开的。
480 |
481 | ```js
482 | app.render('email', function(err, html) {
483 | // ...
484 | });
485 |
486 | app.render('email', {name:'Tobi'}, function(err, html) {
487 | // ...
488 | });
489 | ```
490 |
491 | ####app.route(path)
492 | 返回一个单例模式的路由的实例,之后你可以在其上施加各种HTTP动作的中间件。使用`app.route()`来避免重复路由名字(因此错字错误)--说的意思应该是使用`app.router()`这个单例方法来避免同一个路径多个路由实例。
493 | ```js
494 | var app = express();
495 |
496 | app.route('/events')
497 | .all(function(req, res, next) {
498 | // runs for all HTTP verbs first
499 | // think of it as route specific middleware!
500 | })
501 | .get(function(req, res, next) {
502 | res.json(...);
503 | })
504 | .post(function(req, res, next) {
505 | // maybe add a new event...
506 | })
507 |
508 | ```
509 | ####app.set(name, value)
510 | 给`name`设置项赋`value`值,`name`是[app settings table][24]中属性的一项。
511 | 对于一个类型是布尔型的属性调用`app.set('foo', ture)`等价于调用`app.enable('foo')`。同样的,调用`app.set('foo', false)`等价于调用`app.disable('foo')`。
512 | 可以使用`app.get()`来取得设置的值:
513 | ```js
514 | app.set('title', 'My Site');
515 | app.get('title'); // 'My Site'
516 | ```
517 | **Application Settings**
518 | 如果`name`是程序设置之一,它将影响到程序的行为。下边列出了程序中的设置。
519 | |Property|Type|Value|Default|
520 | |:---:|:---:|:---:|:---:|
521 | |case sensitive routing|Boolean|启用区分大小写。|不启用。对`/Foo`和`/foo`处理是一样。|
522 | |env|String|环境模型。|process.env.NODE_ENV(NODE_ENV环境变量)或者"development"|
523 | |etag|Varied|设置`ETag`响应头。可取的值,可以查阅[etag options table][25]。更多关于[HTTP ETag header][26]。|weak|
524 | |jsonp callback name|String|指定默认JSONP回调的名称。|?callback=|
525 | |json replacer|String|JSON替代品回调|null|
526 | |json spaces|Number|当设置了这个值后,发送缩进空格美化过的JSON字符串。|Disabled|
527 | |query parser|Varied|设置值为`false`来禁用`query parser`,或者设置`simple`,`extended`,也可以自己实现`query string`解析函数。`simple`基于`Node`原生的`query`解析,[querystring][27]。|"extend"|
528 | |strict routing|Boolean|启用严格的路由。|不启用。对`/foo`和`/foo/`的路由处理是一样。|
529 | |subdomain offset|Number|用来删除访问子域的主机点分部分的个数|2|
530 | |trust proxy|Varied|指示`app`在一个反向代理的后面,使用`x-Forwarded-*`来确定连接和客户端的IP地址。注意:`X-Forwarded-*`头部很容易被欺骗,所有检测客户端的IP地址是靠不住的。`trust proxy`默认不启用。当启用时,Express尝试通过前端代理或者一系列代理来获取已连接的客户端IP地址。`req.ips`属性包含了已连接客户端IP地址的一个数组。为了启动它,需要设置在下面[trust proxy options table][28]中定义的值。`trust proxy`的设置实现使用了`proxy-addr`包。如果想获得更多的信息,可以查阅它的文档|Disable|
531 | |views|String or Array|`view`所在的目录或者目录数组。如果是一个数组,将按在数组中的顺序来查找`view`。|process.cwd() + '/views'|
532 | |view cache|Boolean|启用视图模板编译缓存。|在生成环境默认开启。|
533 | |view engine|String|省略时,默认的引擎被扩展使用。||
534 | |x-powered-by|Boolean|启用`X-Powered-By:Express`HTTP头部|true|
535 |
536 | **Options for `trust proxy` settings**
537 | 查阅[Express behind proxies][29]来获取更多信息。
538 |
539 |
540 | | Type | Value |
541 |
542 |
543 | | Boolean |
544 |
545 | 如果为true,客户端的IP地址作为X-Forwarded-*头部的最左边的条目。如果为false,可以理解为app直接与英特网直连,客户端的IP地址衍生自req.connection.remoteAddress。false是默认设置。
546 | |
547 |
548 |
549 | | IP addresses |
550 |
551 | 一个IP地址,子网,或者一组IP地址,和委托子网。下面列出的是一个预先配置的子网名列表。
552 |
553 | - loopback -
127.0.0.1/8, ::1/128
554 | - linklocal -
169.254.0.0/16, fe80::/10
555 | - uniquelocal -
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7
556 |
557 | 使用下面方法中的任何一种来设置IP地址:
558 | app.set('trust proxy', 'loopback') app.set('trust proxy', 'loopback, 123.123.123.123') app.set('trust proxy', 'loopback, linklocal, uniquelocal') app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal'])
562 | 当指定IP地址之后, 这个IP地址或子网会被设置了这个IP地址或子网的`app`排除在外, 最靠近程序服务的没有委托的地址将被看做客户端IP地址。
563 | |
564 |
565 |
566 | | Number |
567 |
568 | 信任从反向代理到app中间小于等于n跳的连接为客户端。
569 | |
570 |
571 |
572 | | Function |
573 |
574 | 客户自定义委托代理信任机制。如果你使用这个,请确保你自己知道你在干什么。
575 | app.set('trust proxy', function (ip) {
576 | if (ip === '127.0.0.1' || ip === '123.123.123.123') return true; else return false;
578 | })
579 | |
580 |
581 |
582 |
583 |
584 | **Options for `etag` settings**
585 | `ETag`功能的实现使用了[etag][30]包。如果你需要获得更多的信息,你可以查阅它的文档。
586 |
587 |
588 | | Type | Value |
589 |
590 |
591 | | Boolean |
592 |
593 | 设置为true,启用weak ETag。这个是默认设置。设置false,禁用所有的ETag。
594 | |
595 |
596 |
597 | | String |
598 |
599 | 如果是strong,使能strong ETag。如果是weak,启用weak ETag。
600 | |
601 |
602 |
603 | | Function |
604 |
605 | 客户自定义`ETag`方法的实现. 如果你使用这个,请确保你自己知道你在干什么。
606 | app.set('etag', function (body, encoding) {
607 | return generateHash(body, encoding); })
609 | |
610 |
611 |
612 |
613 |
614 | ####app.use([path,], function [, function...])
615 | 挂载[中间件][31]方法到路径上。如果路径未指定,那么默认为"/"。
616 | >一个路由将匹配任何路径如果这个路径以这个路由设置路径后紧跟着"/"。比如:`app.use('/appale', ...)`将匹配"/apple","/apple/images","/apple/images/news"等。
617 |
618 | >中间件中的`req.originalUrl`是`req.baseUrl`和`req.path`的组合,如下面的例子所示。
619 | >```js
620 | >app.use('/admin', function(req, res, next) {
621 | >// GET 'http://www.example.com/admin/new'
622 | >console.log(req.originalUrl); // '/admin/new'
623 | >console.log(req.baseUrl); // '/admin'
624 | >console.log(req.path);// '/new'
625 | >});
626 | >```
627 |
628 | 在一个路径上挂载一个中间件之后,每当请求的路径的前缀部分匹配了这个路由路径,那么这个中间件就会被执行。
629 | 由于默认的路径为`/`,中间件挂载没有指定路径,那么对于每个请求,这个中间件都会被执行。
630 | ```js
631 | // this middleware will be executed for every request to the app.
632 | app.use(function(req, res, next) {
633 | console.log('Time: %d', Date.now());
634 | next();
635 | });
636 | ```
637 | 中间件方法是顺序处理的,所以中间件包含的顺序是很重要的。
638 | ```js
639 | // this middleware will not allow the request to go beyond it
640 | app.use(function(req, res, next) {
641 | res.send('Hello World');
642 | });
643 |
644 | // this middleware will never reach this route
645 | app.use('/', function(req, res) {
646 | res.send('Welcome');
647 | });
648 |
649 | ```
650 | 路径可以是代表路径的一串字符,一个路径模式,一个匹配路径的正则表达式,或者他们的一组集合。
651 |
652 | >下面是路径的简单的例子。
653 |
654 |
655 |
656 |
657 | | Type |
658 | Example |
659 |
660 |
661 |
662 |
663 | | Path |
664 |
665 | app.use('/abcd', function (req, res, next) {
667 | next();
668 | })
669 | |
670 |
671 |
672 | | Path Pattern |
673 |
674 | app.use('/abc?d', function (req, res, next) {
676 | next();
677 | })
678 |
679 | app.use('/ab+cd', function (req, res, next) {
681 | next();
682 | })
683 |
684 | app.use('/ab\*cd', function (req, res, next) {
686 | next();
687 | })
688 |
689 | app.use('/a(bc)?d', function (req, res, next) {
691 | next();
692 | })
693 | |
694 |
695 |
696 | | Regular Expression |
697 |
698 | app.use(/\/abc|\/xyz/, function (req, res, next) {
700 | next();
701 | })
702 | |
703 |
704 |
705 | | Array |
706 |
707 | app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) {
709 | next();
710 | })
711 | |
712 |
713 |
714 |
715 |
716 | 方法可以是一个中间件方法,一系列中间件方法,一组中间件方法或者他们的集合。由于`router`和`app`实现了中间件接口,你可以像使用其他任一中间件方法那样使用它们。
717 |
718 |
719 |
720 | | Usage |
721 | Example |
722 |
723 |
724 |
725 |
726 | | 单个中间件 |
727 | 你可以局部定义和挂载一个中间件。
728 | app.use(function (req, res, next) {
729 | next();
730 | })
731 |
732 | 一个router是有效的中间件。
733 | var router = express.Router();
734 | router.get('/', function (req, res, next) {
735 | next();
736 | })
737 | app.use(router);
738 |
739 | 一个Express程序是一个有效的中间件。
740 | var subApp = express();
741 | subApp.get('/', function (req, res, next) {
742 | next();
743 | })
744 | app.use(subApp);
745 |
746 | |
747 |
748 |
749 | | 一系列中间件 |
750 |
751 | 对于一个相同的挂载路径,你可以挂载超过一个的中间件。
752 | var r1 = express.Router();
753 | r1.get('/', function (req, res, next) {
754 | next();
755 | })
756 |
757 | var r2 = express.Router();
758 | r2.get('/', function (req, res, next) {
759 | next();
760 | })
761 |
762 | app.use(r1, r2);
763 |
764 | |
765 |
766 |
767 | | 一组中间件 |
768 |
769 | 在逻辑上使用一个数组来组织一组中间件。如果你传递一组中间件作为第一个或者唯一的参数,接着你需要指定挂载的路径。
770 | var r1 = express.Router();
771 | r1.get('/', function (req, res, next) {
772 | next();
773 | })
774 |
775 | var r2 = express.Router();
776 | r2.get('/', function (req, res, next) {
777 | next();
778 | })
779 |
780 | app.use('/', [r1, r2]);
781 |
782 | |
783 |
784 |
785 | | 组合 |
786 |
787 | 你可以组合下面的所有方法来挂载中间件。
788 | function mw1(req, res, next) { next(); }
789 | function mw2(req, res, next) { next(); }
790 |
791 | var r1 = express.Router();
792 | r1.get('/', function (req, res, next) { next(); });
793 |
794 | var r2 = express.Router();
795 | r2.get('/', function (req, res, next) { next(); });
796 |
797 | var subApp = express();
798 | subApp.get('/', function (req, res, next) { next(); });
799 |
800 | app.use(mw1, [mw2, r1, r2], subApp);
801 |
802 | |
803 |
804 |
805 |
806 |
807 | 下面是一些例子,在`Express`程序中使用`express.static`中间件。
808 | 为程序托管位于程序目录下的`public`目录下的静态资源:
809 | ```js
810 | // GET /style.css etc
811 | app.use(express.static(__dirname + '/public'));
812 | ```
813 | 在`/static`路径下挂载中间件来提供静态资源托管服务,只当请求是以`/static`为前缀的时候。
814 | ```js
815 | // GET /static/style.css etc.
816 | app.use('/static', express.static(express.__dirname + '/public'));
817 | ```
818 | 通过在设置静态资源中间件之后加载日志中间件来关闭静态资源请求的日志。
819 | ```js
820 | app.use(express.static(__dirname + '/public'));
821 | app.use(logger());
822 | ```
823 | 托管静态资源从不同的路径,但`./public`路径比其他更容易被匹配:
824 | ```js
825 | app.use(express.static(__dirname + '/public'));
826 | app.use(express.static(__dirname + '/files'));
827 | app.use(express.static(__dirname + '/uploads'));
828 | ```
829 |
830 | ##Request
831 | `req`对象代表了一个HTTP请求,其具有一些属性来保存请求中的一些数据,比如`query string`,`parameters`,`body`,`HTTP headers`等等。在本文档中,按照惯例,这个对象总是简称为`req`(http响应简称为`res`),但是它们实际的名字由这个回调方法在那里使用时的参数决定。
832 | 如下例子:
833 | ```js
834 | app.get('/user/:id', function(req, res) {
835 | res.send('user' + req.params.id);
836 | });
837 | ```
838 | 其实你也可以这样写:
839 | ```js
840 | app.get('/user/:id', function(request, response) {
841 | response.send('user' + request.params.id);
842 | });
843 | ```
844 |
845 | ###Properties
846 | 在`Express 4`中,`req.files`默认在`req`对象中不再是可用的。为了通过`req.files`对象来获得上传的文件,你可以使用一个`multipart-handling`(多种处理的工具集)中间件,比如`busboy`,`multer`,`formidable`,`multipraty`,`connect-multiparty`或者`pez`。
847 |
848 | ####req.app
849 | 这个属性持有`express`程序实例的一个引用,其可以作为中间件使用。
850 | 如果你按照这个模式,你创建一个模块导出一个中间件,这个中间件只在你的主文件中`require()`它,那么这个中间件可以通过`req.app`来获取express的实例。
851 | 例如:
852 | ```js
853 | // index.js
854 | app.get("/viewdirectory", require('./mymiddleware.js'));
855 | ```
856 |
857 | ```js
858 | // mymiddleware.js
859 | module.exports = function(req, res) {
860 | res.send('The views directory is ' + req.app.get('views'));
861 | };
862 | ```
863 |
864 | ####req.baseUrl
865 | 一个路由实例挂载的Url路径。
866 | ```js
867 | var greet = express.Router();
868 | greet.get('/jp', function(req, res) {
869 | console.log(req.baseUrl); // greet
870 | res.send('Konichiwa!');
871 | });
872 | app.use('/greet', greet);
873 | ```
874 | 即使你使用的路径模式或者一系列路径模式来加载路由,`baseUrl`属性返回匹配的字符串,而不是路由模式。下面的例子,`greet`路由被加载在两个路径模式上。
875 | ```js
876 | app.use(['/gre+t', 'hel{2}o'], greet); // load the on router on '/gre+t' and '/hel{2}o'
877 | ```
878 | 当一个请求路径是`/greet/jp`,`baseUrl`是`/greet`,当一个请求路径是`/hello/jp`,`req.baseUrl`是`/hello`。
879 | `req.baseUrl`和`app`对象的[mountpath][32]属性相似,除了`app.mountpath`返回的是路径匹配模式。
880 |
881 | ####req.body
882 | 在请求的body中保存的是提交的一对对键值数据。默认情况下,它是`undefined`,当你使用比如`body-parser`和`multer`这类解析`body`数据的中间件时,它是填充的。
883 | 下面的例子,给你展示了怎么使用`body-parser`中间件来填充`req.body`。
884 | ```js
885 | var app = require('express');
886 | var bodyParser = require('body-parser');
887 | var multer = require('multer');// v1.0.5
888 | var upload = multer(); // for parsing multipart/form-data
889 | app.use(bodyParser.json()); // for parsing application/json
890 | app.use(bodyParser.urlencoded({extended:true})); // for parsing application/x-www-form-urlencoded
891 |
892 | app.post('/profile', upload.array(), function(req, res, next) {
893 | console.log(req.body);
894 | res.json(req.body);
895 | });
896 | ```
897 |
898 | ####req.cookies
899 | 当使用`cookie-parser`中间件的时候,这个属性是一个对象,其包含了请求发送过来的`cookies`。如果请求没有带`cookies`,那么其值为`{}`。
900 | ```js
901 | // Cookie: name=tj
902 | req.cookies.name
903 | // => "tj"
904 | ```
905 | 获取更多信息,问题,或者关注,可以查阅[cookie-parser][33]。
906 | ####req.fresh
907 | 指示这个请求是否是新鲜的。其和`req.stale`是相反的。
908 | 当`cache-control`请求头没有`no-cache`指示和下面中的任一一个条件为`true`,那么其就为`true`:
909 |
910 | - `if-modified-since`请求头被指定,和`last-modified`请求头等于或者早于`modified`响应头。
911 | - `if-none-match`请求头是`*`。
912 | - `if-none-match`请求头在被解析进它的指令之后,不匹配`etag`响应头(完全不知道什么鬼)。
913 |
914 | ```js
915 | req.fresh
916 | // => true
917 | ```
918 |
919 | ####req.hostname
920 | 包含了源自`Host`HTTP头部的`hostname`。
921 | 当`trust proxy`设置项被设置为启用值,`X-Forwarded-Host`头部被使用来代替`Host`。这个头部可以被客户端或者代理设置。
922 | ```js
923 | // Host: "example.com"
924 | req.hostname
925 | // => "example.com"
926 | ```
927 | ####req.ips
928 | 当`trust proxy`设置项被设置为启用值,这个属性包含了一组在`X-Forwarded-For`请求头中指定的IP地址。不然,其就包含一个空的数组。这个头部可以被客户端或者代理设置。
929 | 例如,如果`X-Forwarded-For`是`client`,`proxy1`,`proxy2`,`req.ips`就是`["clinet", "proxy1", "proxy2"]`,这里`proxy2`就是最远的下游。
930 | ####req.originalUrl
931 | >`req.url`不是一个原生的`Express`属性,它继承自[Node's http module][34]。
932 |
933 | 这个属性很像`req.url`;然而,其保留了原版的请求链接,允许你自由地重定向`req.url`到内部路由。比如,`app.use()`的`mounting`特点可以重定向`req.url`跳转到挂载点。
934 | ```js
935 | // GET /search?q=something
936 | req.originalUrl
937 | // => "/search?q=something"
938 | ```
939 |
940 | ####req.params
941 | 一个对象,其包含了一系列的属性,这些属性和在路由中命名的参数名是一一对应的。例如,如果你有`/user/:name`路由,`name`属性可作为`req.params.name`。这个对象默认值为`{}`。
942 | ```js
943 | // GET /user/tj
944 | req.params.name
945 | // => "tj"
946 | ```
947 | 当你使用正则表达式来定义路由规则,捕获组的组合一般使用`req.params[n]`,这里的`n`是第几个捕获租。这个规则被施加在无名通配符匹配,比如`/file/*`的路由:
948 | ```js
949 | // GET /file/javascripts/jquery.js
950 | req.params[0]
951 | // => "javascripts/jquery.js"
952 | ```
953 | ####req.path
954 | 包含请求URL的部分路径。
955 | ```js
956 | // example.com/users?sort=desc
957 | req.path
958 | // => "/users"
959 | ```
960 |
961 | > 当在一个中间件中被调用,挂载点不包含在`req.path`中。你可以查阅[app.use()][35]获得跟多的信息。
962 |
963 | ####req.protocol
964 | 请求的协议,一般为`http`,当启用TLS加密,则为`https`。
965 | 当`trust proxy`设置一个启用的参数,如果存在`X-Forwarded-Proto`头部的话,其将被信赖和使用。这个头部可以被客户端或者代理设置。
966 | ```js
967 | req.ptotocol
968 | // => "http"
969 | ```
970 |
971 | ####req.query
972 | 一个对象,为每一个路由中的`query string`参数都分配一个属性。如果没有`query string`,它就是一个空对象,`{}`。
973 | ```js
974 | // GET /search?q=tobi+ferret
975 | req.query.q
976 | // => "tobi ferret"
977 |
978 | // GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
979 | req.query.order
980 | // => "desc"
981 |
982 | req.query.shoe.color
983 | // => "blue"
984 |
985 | req.query.shoe.type
986 | // => "converse"
987 | ```
988 |
989 | ####req.route
990 | 当前匹配的路由,其为一串字符。比如:
991 | ```js
992 | app.get('/user/:id?', function userIdHandler(req, res) {
993 | console.log(req.route);
994 | res.send('GET')
995 | })
996 | ```
997 | 前面片段的输出为:
998 | ```js
999 | { path:"/user/:id?"
1000 | stack:
1001 | [
1002 | { handle:[Function:userIdHandler],
1003 | name:"userIdHandler",
1004 | params:undefined,
1005 | path:undefined,
1006 | keys:[],
1007 | regexp:/^\/?$/i,
1008 | method:'get'
1009 | }
1010 | ]
1011 | methods:{get:true}
1012 | }
1013 | ```
1014 | ####req.secure
1015 | 一个布尔值,如果建立的是TLS的连接,那么就为`true`。等价与:
1016 | ```js
1017 | 'https' == req.protocol;
1018 | ```
1019 |
1020 | ####req.signedCookies
1021 | 当使用`cookie-parser`中间件的时候,这个属性包含的是请求发过来的签名`cookies`,不签名的并且为使用做好了准备(这句真不知道怎么翻译了...)。签名`cookies`驻留在不同的对象中来体现开发者的意图;不然,一个恶意攻击可以被施加在`req.cookie`值上(它是很容易被欺骗的)。记住,签名一个`cookie`不是把它藏起来或者加密;而是简单的防止篡改(因为签名使用的加密是私人的)。如果没有发送签名的`cookie`,那么这个属性默认为`{}`。
1022 | ```js
1023 | // Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
1024 | req.signedCookies.user
1025 | // => "tobi"
1026 | ```
1027 | 为了获取更多的信息,问题或者关注,可以参阅[cookie-parser][36]。
1028 |
1029 | ####req.stale
1030 | 指示这个请求是否是`stale`(陈旧的),它与`req.fresh`是相反的。更多信息,可以查看[req.fresh][37]。
1031 | ```js
1032 | req.stale
1033 | // => true
1034 | ```
1035 |
1036 | ####req.subdomains
1037 | 请求中域名的子域名数组。
1038 | ```js
1039 | // Host: "tobi.ferrets.example.com"
1040 | req.subdomains
1041 | // => ["ferrets", "tobi"]
1042 | ```
1043 |
1044 | ####req.xhr
1045 | 一个布尔值,如果`X-Requested-With`的值为`XMLHttpRequest`,那么其为`true`,其指示这个请求是被一个客服端库发送,比如`jQuery`。
1046 | ```js
1047 | req.xhr
1048 | // => true
1049 |
1050 | ```
1051 |
1052 | ###Methods
1053 | ####req.accepts(types)
1054 | 检查这个指定的内容类型是否被接受,基于请求的`Accept` HTTP头部。这个方法返回最佳匹配,如果没有一个匹配,那么其返回`undefined`(在这个case下,服务器端应该返回406和"Not Acceptable")。
1055 | `type`值可以是一个单的`MIME type`字符串(比如`application/json`),一个扩展名比如`json`,一个逗号分隔的列表,或者一个数组。对于一个列表或者数组,这个方法返回最佳项(如果有的话)。
1056 | ```js
1057 | // Accept: text/html
1058 | req.accepts('html');
1059 | // => "html"
1060 |
1061 | // Accept: text/*, application/json
1062 | req.accepts('html');
1063 | // => "html"
1064 |
1065 | req.accepts('text/html');
1066 | // => "text/html"
1067 |
1068 | req.accepts(['json', 'text']);
1069 | // => "json"
1070 |
1071 | req.accepts('application/json');
1072 | // => "application/json"
1073 |
1074 | // Accept: text/*, application/json
1075 | req.accepts('image/png');
1076 | req.accepts('png');
1077 | // => undefined
1078 |
1079 | // Accept: text/*;q=.5, application/json
1080 | req.accepts(['html', 'json']);
1081 | // => "json"
1082 |
1083 | ```
1084 | 获取更多信息,或者如果你有问题或关注,可以参阅[accepts][38]。
1085 |
1086 | ####req.acceptsCharsets(charset[, ...])
1087 | 返回指定的字符集集合中第一个的配置的字符集,基于请求的`Accept-Charset`HTTP头。如果指定的字符集没有匹配的,那么就返回false。
1088 | 获取更多信息,或者如果你有问题或关注,可以参阅[accepts][39]。
1089 |
1090 | ####req.acceptsEncodings(encoding[, ...])
1091 | 返回指定的编码集合中第一个的配置的编码,基于请求的`Accept-Encoding`HTTP头。如果指定的编码集没有匹配的,那么就返回false。
1092 | 获取更多信息,或者如果你有问题或关注,可以参阅[accepts][40]。
1093 |
1094 | ####req.acceptsLanguages(lang [, ...])
1095 | 返回指定的语言集合中第一个的配置的语言,基于请求的`Accept-Language`HTTP头。如果指定的语言集没有匹配的,那么就返回false。
1096 | 获取更多信息,或者如果你有问题或关注,可以参阅[accepts][41]。
1097 |
1098 | ####req.get(field)
1099 | 返回指定的请求HTTP头部的域内容(不区分大小写)。`Referrer`和`Referer`的域内容可互换。
1100 | ```js
1101 | req.get('Content-type');
1102 | // => "text/plain"
1103 |
1104 | req.get('content-type');
1105 | // => "text/plain"
1106 |
1107 | req.get('Something')
1108 | // => undefined
1109 | ```
1110 | 其是`req.header(field)`的别名。
1111 |
1112 | ####req.is(type)
1113 | 如果进来的请求的`Content-type`头部域匹配参数`type`给定的`MIME type`,那么其返回`true`。否则返回`false`。
1114 | ```js
1115 | // With Content-Type: text/html; charset=utf-8
1116 | req.is('html');
1117 | req.is('text/html');
1118 | req.is('text/*');
1119 | // => true
1120 |
1121 | // When Content-Type is application/json
1122 | req.is('json');
1123 | req.is('application/json');
1124 | req.is('application/*');
1125 | // => true
1126 |
1127 | req.is('html');
1128 | // => false
1129 | ```
1130 | 获取更多信息,或者如果你有问题或关注,可以参阅[type-is][42]。
1131 |
1132 | ####req.param(naem, [, defaultValue])
1133 | > 过时的。可以在适合的情况下,使用`req.params`,`req.body`或者`req.query`。
1134 |
1135 | 返回当前参数`name`的值。
1136 | ```js
1137 | // ?name=tobi
1138 | req.param('name')
1139 | // => "tobi"
1140 |
1141 | // POST name=tobi
1142 | req.param('name')
1143 | // => "tobi"
1144 | // /user/tobi for /user/:name
1145 | req.param('name')
1146 | // => "tobi"
1147 | ```
1148 | 按下面给出的顺序查找:
1149 |
1150 | - req.params
1151 | - req.body
1152 | - req.query
1153 |
1154 | 可选的,你可以指定一个`defaultValue`来设置一个默认值,如果这个参数在任何一个请求的对象中都不能找到。
1155 | > 直接通过`req.params`,`req.body`,`req.query`取得应该更加的清晰-除非你确定每一个对象的输入。
1156 | > `Body-parser`中间件必须加载,如果你使用`req.param()`。详细请看[req.body][43]。
1157 |
1158 |
1159 | ##Response
1160 | `res`对象代表了当一个HTTP请求到来时,`Express`程序返回的HTTP响应。在本文档中,按照惯例,这个对象总是简称为`res`(http请求简称为`req`),但是它们实际的名字由这个回调方法在那里使用时的参数决定。
1161 | 例如:
1162 | ```js
1163 | app.get('/user/:id', function(req, res) {
1164 | res.send('user' + req.params.id);
1165 | });
1166 | ```
1167 | 这样写也是一样的:
1168 | ```js
1169 | app.get('/user/:id', function(request, response) {
1170 | response.send('user' + request.params.id);
1171 | });
1172 |
1173 | ```
1174 |
1175 | ###Properties
1176 | ####res.app
1177 | 这个属性持有`express`程序实例的一个引用,其可以在中间件中使用。
1178 | `res.app`和请求对象中的`req.app`属性是相同的。
1179 |
1180 |
1181 | ####res.headersSent
1182 | 布尔类型的属性,指示这个响应是否已经发送HTTP头部。
1183 | ```js
1184 | app.get('/', function(req, res) {
1185 | console.log(res.headersSent); // false
1186 | res.send('OK'); // send之后就发送了头部
1187 | console.log(res.headersSent); // true
1188 | });
1189 | ```
1190 |
1191 | ####res.locals
1192 | 一个对象,其包含了响应的能够反应出请求的本地参数和因此只提供给视图渲染,在请求响应的周期内(如果有的话)--我要翻译吐了。否则,其和`app.locals`是一样的。(不知道翻译的什么...)
1193 | 这个参数在导出请求级别的信息是很有效的,这些信息比如请求路径,已认证的用户,用户设置等等。
1194 | ```js
1195 | app.use(function(req, res, next) {
1196 | res.locals.user = req.user;
1197 | res.locals.authenticated = !req.user.anonymous;
1198 | next();
1199 | });
1200 | ```
1201 |
1202 | ###Methods
1203 | ####res.append(field [, value])
1204 | > res.append()方法在`Expresxs`4.11.0以上版本才支持。
1205 |
1206 | 在指定的`field`的HTTP头部追加特殊的值`value`。如果这个头部没有被设置,那么将用`value`新建这个头部。`value`可以是一个字符串或者数组。
1207 | 注意:在`res.append()`之后调用`app.set()`函数将重置前面设置的值。
1208 | ```js
1209 | res.append('Lind', ['', '']);
1210 | res.append('Set-Cookie', 'foo=bar;Path=/;HttpOnly');
1211 | res.append('Warning', '199 Miscellaneous warning');
1212 | ```
1213 |
1214 | ####res.attachment([filename])
1215 | 设置HTTP响应的`Content-Disposition`头内容为"attachment"。如果提供了`filename`,那么将通过`res.type()`获得扩展名来设置`Content-Type`,并且设置`Content-Disposition`内容为"filename="parameter。
1216 | ```js
1217 | res.attachment();
1218 | // Content-Disposition: attachment
1219 |
1220 | res.attachment('path/to/logo.png');
1221 | // Content-Disposition: attachment; filename="logo.png"
1222 | // Content-Type: image/png
1223 | ```
1224 |
1225 | ####res.cookie(name, value [,options])
1226 | 设置`name`和`value`的`cookie`,`value`参数可以是一串字符或者是转化为json字符串的对象。
1227 | options是一个对象,其可以有下列的属性。
1228 | |属性|类型|描述|
1229 | |:---:|:---:|:---:|
1230 | |domain|String|设置cookie的域名。默认是你本app的域名。|
1231 | |expires|Date|cookie的过期时间,GMT格式。如果没有指定或者设置为0,则产生新的cookie。|
1232 | |httpOnly|Boolean|这个cookie只能被web服务器获取的标示。|
1233 | |maxAge|String|是设置过去时间的方便选项,其为过期时间到当前时间的毫秒值。|
1234 | |path|String|cookie的路径。默认值是`/`。|
1235 | |secure|Boolean|标示这个cookie只用被`HTTPS`协议使用。|
1236 | |signed|Boolean|指示这个cookie应该是签名的。|
1237 |
1238 | > res.cookie()所作的都是基于提供的`options`参数来设置`Set-Cookie`头部。没有指定任何的`options`,那么默认值在`RFC6265`中指定。
1239 |
1240 | 使用实例:
1241 | ```js
1242 | res.cookie('name', 'tobi', {'domain':'.example.com', 'path':'/admin', 'secure':true});
1243 | res.cookie('remenberme', '1', {'expires':new Date(Date.now() + 90000), 'httpOnly':true});
1244 | ```
1245 | `maxAge`是一个方便设置过期时间的方便的选项,其以当前时间开始的毫秒数来计算。下面的示例和上面的第二条功效一样。
1246 | ```js
1247 | res.cookie('rememberme', '1', {'maxAge':90000}, "httpOnly":true);
1248 | ```
1249 | 你可以设置传递一个对象作为`value`的参数。然后其将被序列化为Json字符串,被`bodyParser()`中间件解析。
1250 | ```js
1251 | res.cookie('cart', {'items':[1, 2, 3]});
1252 | res.cookie('cart', {'items':[1, 2, 3]}, {'maxAge':90000});
1253 | ```
1254 | 当我们使用`cookie-parser`中间件的时候,这个方法也支持签名的cookie。简单地,在设置`options`时包含`signed`选项为`true`。然后`res.cookie()`将使用传递给`cookieParser(secret)`的密钥来签名这个值。
1255 | ```js
1256 | res.cookie('name', 'tobi', {'signed':true});
1257 | ```
1258 |
1259 |
1260 | ####res.clearCookie(name [,options])
1261 | 根据指定的`name`清除对应的cookie。更多关于`options`对象可以查阅`res.cookie()`。
1262 | ```js
1263 | res.cookie('name', 'tobi', {'path':'/admin'});
1264 | res.clearCookie('name', {'path':'admin'});
1265 | ```
1266 | ####res.download(path, [,filename], [,fn])
1267 | 传输`path`指定文件作为一个附件。通常,浏览器提示用户下载。默认情况下,`Content-Disposition`头部"filename="的参数为`path`(通常会出现在浏览器的对话框中)。通过指定`filename`参数来覆盖默认值。
1268 | 当一个错误发生时或者传输完成,这个方法将调用`fn`指定的回调方法。这个方法使用`res.sendFile()`来传输文件。
1269 | ```js
1270 | res.download('/report-12345.pdf');
1271 |
1272 | res.download('/report-12345.pdf', 'report.pdf');
1273 |
1274 | res.download('report-12345.pdf', 'report.pdf', function(err) {
1275 | // Handle error, but keep in mind the response may be partially-sent
1276 | // so check res.headersSent
1277 | if (err) {
1278 | } else {
1279 | // decrement a download credit, etc.
1280 | }
1281 | });
1282 | ```
1283 |
1284 | ####res.end([data] [, encoding])
1285 | 结束本响应的过程。这个方法实际上来自`Node`核心模块,具体的是[response.end() method of http.ServerResponse][44]。
1286 | 用来快速结束请求,没有任何的数据。如果你需要发送数据,可以使用[res.send()][45]和[res.json()][46]这类的方法。
1287 | ```js
1288 | res.end();
1289 | res.status(404).end();
1290 | ```
1291 | ####res.format(object)
1292 | 进行内容协商,根据请求的对象中`Accept`HTTP头部指定的接受内容。它使用[req.accepts()][47]来选择一个句柄来为请求服务,这些句柄按质量值进行排序。如果这个头部没有指定,那么第一个方法默认被调用。当不匹配时,服务器将返回`406`"Not Acceptable",或者调用`default`回调。
1293 | `Content-Type`请求头被设置,当一个回调方法被选择。然而你可以改变他,在这个方法中使用这些方法,比如`res.set()`或者`res.type()`。
1294 | 下面的例子,将回复`{"message":"hey"}`,当请求的对象中`Accept`头部设置成"application/json"或者"*/json"(不过如果是`*/*`,然后这个回复就是"hey")。
1295 | ```js
1296 | res.format({
1297 | 'text/plain':function() {
1298 | res.send('hey')'
1299 | },
1300 | 'text/html':function() {
1301 | res.send('hey
');
1302 | },
1303 | 'application/json':function() {
1304 | res.send({message:'hey'});
1305 | },
1306 | 'default':function() {
1307 | res.status(406).send('Not Acceptable');
1308 | }
1309 | })
1310 | ```
1311 | 除了规范化的MIME类型之外,你也可以使用拓展名来映射这些类型来避免冗长的实现:
1312 | ```js
1313 | res.format({
1314 | text:function() {
1315 | res.send('hey');
1316 | },
1317 | html:function() {
1318 | res.send('hey
');
1319 | },
1320 | json:function() {
1321 | res.send({message:'hey'});
1322 | }
1323 | })
1324 | ```
1325 | ####res.get(field)
1326 | 返回`field`指定的HTTP响应的头部。匹配是区分大小写。
1327 | ```js
1328 | res.get('Content-Type');
1329 | // => "text/plain"
1330 | ```
1331 | ####res.json([body])
1332 | 发送一个json的响应。这个方法和将一个对象或者一个数组作为参数传递给`res.send()`方法的效果相同。不过,你可以使用这个方法来转换其他的值到json,例如`null`,`undefined`。(虽然这些都是技术上无效的JSON)。
1333 | ```js
1334 | res.json(null);
1335 | res.json({user:'tobi'});
1336 | res.status(500).json({error:'message'});
1337 |
1338 | ```
1339 |
1340 | ####res.jsonp([body])
1341 | 发送一个json的响应,并且支持JSONP。这个方法和`res.json()`效果相同,除了其在选项中支持JSONP回调。
1342 | ```js
1343 | res.jsonp(null)
1344 | // => null
1345 |
1346 | res.jsonp({user:'tobi'})
1347 | // => {"user" : "tobi"}
1348 |
1349 | res.status(500).jsonp({error:'message'})
1350 | // => {"error" : "message"}
1351 | ```
1352 | 默认情况下,jsonp的回调方法简单写作`callback`。可以通过[jsonp callback name][48]设置来重写它。
1353 | 下面是一些例子使用JSONP响应,使用相同的代码:
1354 | ```js
1355 | // ?callback=foo
1356 | res.jsonp({user:'tobo'})
1357 | // => foo({"user":"tobi"})
1358 |
1359 | app.set('jsonp callback name', 'cb')
1360 |
1361 | // ?cb=foo
1362 | res.status(500).jsonp({error:'message'})
1363 | // => foo({"error":"message"})
1364 | ```
1365 | ####res.links(links)
1366 | 连接这些`links`,`links`是以传入参数的属性形式提供,连接之后的内容用来填充响应的Link HTTP头部。
1367 | ```js
1368 | res.links({
1369 | next:'http://api.example.com/users?page=2',
1370 | last:'http://api.example.com/user?page=5'
1371 | });
1372 | ```
1373 | 效果:
1374 | ```js
1375 | Link:;rel="next",
1376 | ;rel="last"
1377 | ```
1378 |
1379 | ####res.location(path)
1380 | 设置响应的`Location`HTTP头部为指定的`path`参数。
1381 | ```js
1382 | res.location('/foo/bar');
1383 | res.location('http://example.com');
1384 | res.location('back');
1385 | ```
1386 | 当`path`参数为`back`时,其具有特殊的意义,其指定URL为请求对象的`Referer`头部指定的URL。如果请求中没有指定,那么其即为"/"。
1387 |
1388 | >Express传递指定的URL字符串作为回复给浏览器响应中的`Location`头部的值,不检测和操作,除了当是`back`这个case时。浏览器有推导预期URL从当前的URL或者指定的URL,和在`Location`指定的URL的责任;相应地重定向它。(我也不知道翻译的什么...)
1389 |
1390 | ####res.redirect([status,] path)
1391 | 重定向来源于指定`path`的URL,以及指定的[HTTP status code][49]`status`。如果你没有指定`status`,status code默认为"302 Found"。
1392 | ```js
1393 | res.redirect('/foo/bar');
1394 | res.redirect('http://example.com');
1395 | res.redirect(301, 'http://example.com');
1396 | res.redirect('../login');
1397 | ```
1398 | 重定向也可以是完整的URL,来重定向到不同的站点。
1399 | ```js
1400 | res.redirect('http://google.com');
1401 | ```
1402 | 重定向也可以相对于主机的根路径。比如,如果程序的路径为`http://example.com/admin/post/new`,那么下面将重定向到`http://example.com/admim`:
1403 | ```js
1404 | res.redirect('/admin');
1405 | ```
1406 | 重定向也可以相对于当前的URL。比如,来之于`http://example.com/blog/admin/`(注意结尾的`/`),下面将重定向到`http://example.com/blog/admin/post/new`。
1407 | ```js
1408 | res.redirect('post/new');
1409 | ```
1410 | 如果来至于`http://example.com/blog/admin`(没有尾部`/`),重定向`post/new`,将重定向到`http://example.com/blog/post/new`。如果你觉得上面很混乱,可以把路径段认为目录(有'/')或者文件,这样是可以的。相对路径的重定向也是可以的。如果你当前的路径为`http://example.com/admin/post/new`,下面的操作将重定向到`http://example.com/admin/post`:
1411 | ```js
1412 | res.redirect('..');
1413 | ```
1414 | `back`将重定向请求到[referer][50],当没有`referer`的时候,默认为`/`。
1415 | ```js
1416 | res.redirect('back');
1417 | ```
1418 |
1419 | ####res.render(view [, locals] [, callback])
1420 | 渲染一个视图,然后将渲染得到的HTML文档发送给客户端。可选的参数为:
1421 |
1422 | - `locals`,定义了视图本地参数属性的一个对象。
1423 | - `callback`,一个回调方法。如果提供了这个参数,`render`方法将返回错误和渲染之后的模板,并且不自动发送响应。当有错误发生时,可以在这个回调内部,调用`next(err)`方法。
1424 |
1425 | >本地变量缓存使能视图缓存。在开发环境中缓存视图,需要手动设置为true;视图缓存在生产环境中默认开启。
1426 |
1427 | ```js
1428 |
1429 | // send the rendered view to the client
1430 | res.render('index');
1431 |
1432 | // if a callback is specified, the render HTML string has to be sent explicitly
1433 |
1434 | res.render('index', function(err, html) {
1435 | res.send(html);
1436 | });
1437 |
1438 | // pass a local variable to the view
1439 | res.render('user', {name:'Tobi'}, function(err, html) {
1440 | // ...
1441 | });
1442 | ```
1443 |
1444 |
1445 | ####res.send([body])
1446 | 发送HTTP响应。
1447 | `body`参数可以是一个`Buffer`对象,一个字符串,一个对象,或者一个数组。比如:
1448 | ```js
1449 | res.send(new Buffer('whoop'));
1450 | res.send({some:'json'});
1451 | res.send('some html
');
1452 | res.status(404).send('Sorry, we cannot find that!');
1453 | res.status(500).send({ error: 'something blew up' });
1454 |
1455 | ```
1456 | 对于一般的非流请求,这个方法可以执行许多有用的的任务:比如,它自动给`Content-Length`HTTP响应头赋值(除非先前定义),也支持自动的HEAD和HTTP缓存更新。
1457 | 当参数是一个`Buffer`对象,这个方法设置`Content-Type`响应头为`application/octet-stream`,除非事先提供,如下所示:
1458 | ```js
1459 | res.set('Content-Type', 'text/html');
1460 | res.send(new Buffer('some html
'));
1461 | ```
1462 | 当参数是一个字符串,这个方法设置`Content-Type`响应头为`text/html`:
1463 | ```js
1464 | res.send('some html
');
1465 | ```
1466 |
1467 | 当参数是一个对象或者数组,Express使用JSON格式来表示:
1468 | ```js
1469 | res.send({user:'tobi'});
1470 | res.send([1, 2, 3]);
1471 | ```
1472 |
1473 | ####res.sendFile(path [, options] [, fn])
1474 | > `res.sendFile()`从`Express v4.8.0`开始支持。
1475 |
1476 | 传输`path`指定的文件。根据文件的扩展名设置`Content-Type`HTTP头部。除非在`options`中有关于`root`的设置,`path`一定是关于文件的绝对路径。
1477 | 下面的表提供了`options`参数的细节:
1478 | |属性|描述|默认值|可用版本|
1479 | |:---:|:---:|:---:|:---:|
1480 | |maxAge|设置`Cache-Control`的`max-age`属性,格式为毫秒数,或者是[ms format][51]的一串字符串|0||
1481 | |root|相对文件名的根目录|||
1482 | |lastModified|设置`Last-Modified`头部为此文件在系统中的最后一次修改时间。设置`false`来禁用它|Enable|4.9.0+|
1483 | |headers|一个对象,包含了文件所在的sever的HTTP头部。(不知道怎么翻译了)|||
1484 | |dotfiles|是否支持点开头文件名的选项。可选的值"allow","deny","ignore"|"ignore"||
1485 |
1486 | 当传输完成或者发生了什么错误,这个方法调用`fn`回调方法。如果这个回调参数指定了和一个错误发生,回调方法必须明确地通过结束请求-响应循环或者传递控制到下个路由来处理响应过程。
1487 | 下面是使用了所有参数的使用`res.sendFile()`的例子:
1488 | ```js
1489 | app.get('/file/:name', function(req, res, next) {
1490 |
1491 | var options = {
1492 | root:__dirname + '/public',
1493 | dotfile:'deny',
1494 | headers:{
1495 | 'x-timestamp':Date.now(),
1496 | 'x-sent':true
1497 | }
1498 | };
1499 |
1500 | var fileName = req.params.name;
1501 | res.sendFile(fileName, options, function(err) {
1502 | if (err) {
1503 | console.log(err);
1504 | res.status(err.status).end();
1505 | }
1506 | else {
1507 | console.log('sent', fileName);
1508 | }
1509 | });
1510 |
1511 |
1512 |
1513 | });
1514 |
1515 | ```
1516 | `res.sendFile`提供了文件服务的细粒度支持,如下例子说明:
1517 | ```js
1518 | app.get('/user/:uid/photos/:file', function(req, res) {
1519 | var uid = req.params.uid
1520 | , file = req.params.file;
1521 |
1522 |
1523 | req.user.mayViewFilesFrom(uid, function(yes) {
1524 | if (yes) {
1525 | res.sendFile('/upload/' + uid + '/' + file);
1526 | }
1527 | else {
1528 | res.status(403).send('Sorry! you cant see that.');
1529 | }
1530 | });
1531 |
1532 | })
1533 | ```
1534 | 获取更多信息,或者你有问题或者关注,可以查阅[send][52]。
1535 |
1536 | ####res.sendStatus(statusCode)
1537 | 设置响应对象的`HTTP status code`为`statusCode`并且发送`statusCode`的相应的字符串形式作为响应的Body。
1538 | ```js
1539 | res.sendStatus(200); // equivalent to res.status(200).send('OK');
1540 | res.sendStatus(403); // equivalent to res.status(403).send('Forbidden');
1541 | res.sendStatus(404); // equivalent to res.status(404).send('Not Found');
1542 | res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
1543 | ```
1544 | 如果一个不支持的状态被指定,这个HTTP status依然被设置为`statusCode`并且用这个code的字符串作为Body。
1545 | ```js
1546 | res.sendStatus(2000); // equivalent to res.status(2000).send('2000');
1547 | ```
1548 | [More about HTTP Status Codes][53]
1549 |
1550 | ####res.set(field [, value])
1551 | 设置响应对象的HTTP头部`field`为`value`。为了一次设置多个值,那么可以传递一个对象为参数。
1552 | ```js
1553 | res.set('Content-Type', 'text/plain');
1554 |
1555 | res.set({
1556 | 'Content-Type':'text/plain',
1557 | 'Content-Length':'123',
1558 | 'ETag':'123456'
1559 | })
1560 | ```
1561 | 其和`res.header(field [,value])`效果一致。
1562 |
1563 | ####res.status(code)
1564 | 使用这个方法来设置响应对象的HTTP status。其是Node中[response.statusCode][54]的一个连贯性的别名。
1565 | ```js
1566 | res.status(403).end();
1567 | res.status(400).send('Bad Request');
1568 | res.status(404).sendFile('/absolute/path/to/404.png');
1569 | ```
1570 |
1571 | ####res.type(type)
1572 | 设置`Content-Type`HTTP头部为MIME type,如果这个指定的type能够被[mime.lookup][55]确定。如果`type`包含`/`字符,那么设置`Content-Type`为`type`(我已经晕了)。
1573 | ```js
1574 | res.type('.html'); // => 'text/html'
1575 | res.type('html'); // => 'text/html'
1576 | res.type('json'); // => 'application/json'
1577 | res.type('application/json'); // => 'application/json'
1578 | res.type('png'); // => image/png:
1579 | ```
1580 |
1581 |
1582 | ####res.vary(field)
1583 | 设置`Vary`响应头为`field`,如果已经不在那里。(不懂什么意思)
1584 | ```js
1585 | res.vary('User-Agent').render('docs');
1586 | ```
1587 |
1588 | ##Router
1589 | 一个`router`对象是一个单独的实例关于中间件和路由。你可以认为其是一个"mini-application"(迷你程序),其具有操作中间件和路由方法的能力。每个`Express`程序有一个内建的app路由。
1590 | 路由自身表现为一个中间件,所以你可以使用它作为`app.use()`方法的一个参数或者作为另一个路由的`use()`的参数。
1591 | 顶层的`express`对象有一个`Router()`方法,你可以使用`Router()`来创建一个新的`router`对象。
1592 |
1593 | ####Router([options])
1594 | 如下,可以创建一个路由:
1595 | ```js
1596 | var router = express.Router([options]);
1597 | ```
1598 | `options`参数可以指定路由的行为,其有下列选择:
1599 | |属性|描述|默认值|可用性|
1600 | |:---:|:---:|:---:|:---:|
1601 | |caseSensitive|是否区分大小写|默认不启用。对待`/Foo`和`/foo`一样。||
1602 | |mergeParams|保存父路由的`res.params`。如果父路由参数和子路由参数冲突,子路由参数优先。|false|4.5.0+|
1603 | |strict|使能严格路由。|默认不启用,`/foo`和`/foo/`被路由一样对待处理||
1604 |
1605 | 你可以将`router`当作一个程序,可以在其上添加中间件和HTTP路由方法(例如`get`,`put`,`post`等等)。
1606 | ```js
1607 | // invoked for any requests passed to this router
1608 | router.use(function(req, res, next) {
1609 | // .. some logic here .. like any other middleware
1610 | next();
1611 | });
1612 |
1613 | // will handle any request that ends in /events
1614 | // depends on where the router is "use()'d"
1615 | router.get('/events', function(req, res, next) {
1616 | // ..
1617 | });
1618 |
1619 | ```
1620 | 你可以在一个特别的根URL上挂载一个路由,这样你就以将你的各个路由放到不同的文件中或者甚至是mini的程序。
1621 | ```js
1622 | // only requests to /calendar/* will be sent to our "router"
1623 | app.use('/calendar', router);
1624 | ```
1625 |
1626 | ###Methods
1627 | ####router.all(path, [callback, ...] callback)
1628 | 这个方法和`router.METHOD()`方法一样,除了这个方法会匹配所有的HTTP动作。
1629 | 这个方法对想映射全局的逻辑处理到特殊的路径前缀或者任意匹配是十分有用的。比如,如果你放置下面所示的这个路由在其他路由的前面,那么其将要求从这个点开始的所有的路由进行验证操作和自动加载用户信息。记住,这些全局的逻辑操作,不需要结束请求响应周期:`loaduser`可以执行一个任务,然后调用`next()`来将执行流程移交到随后的路由。
1630 | ```js
1631 | router.all('*', requireAuthentication, loadUser);
1632 | ```
1633 | 相等的形式:
1634 | ```js
1635 | router.all('*', requireAuthentication)
1636 | router.all('*', loadUser);
1637 | ```
1638 | 这是一个白名单全局功能的例子。这个例子很像前面的,不过其仅仅作用于以`/api`开头的路径:
1639 | ```js
1640 | router.all('/api/*', requireAuthentication);
1641 | ```
1642 | ####router.METHOD(path, [callback, ...] callback)
1643 | `router.METHOD()`方法提供了路由方法在`Express`中,这里的`METHOD`是HTTP方法中的一个,比如`GET`,`PUT`,`POST`等等,但`router`中的METHOD是小写的。所以,实际的方法是`router.get()`,`router.put()`,`router.post()`等等。
1644 | 你可以提供多个回调函数,它们的行为和中间件一样,除了这些回调可以通过调用`next('router')`来绕过剩余的路由回调。你可以使用这个机制来为一个路由设置一些前提条件,如果请求没有满足当前路由的处理条件,那么传递控制到随后的路由。
1645 | 下面的片段可能说明了最简单的路由定义。Experss转换path字符串为正则表达式,用于内部匹配传入的请求。在匹配的时候,是不考虑`Query strings`,例如,"GET /"将匹配下面的路由,"GET /?name=tobi"也是一样的。
1646 | ```js
1647 | router.get('/', function(req, res) {
1648 | res.send('Hello World');
1649 | });
1650 | ```
1651 |
1652 | 如果你对匹配的path有特殊的限制,你可以使用正则表达式,例如,下面的可以匹配"GET /commits/71dbb9c"和"GET /commits/71bb92..4c084f9"。
1653 | ```js
1654 | router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res) {
1655 | var from = req.params[0];
1656 | var to = req.params[1];
1657 | res.send('commit range ' + from + '..' + to);
1658 | });
1659 | ```
1660 |
1661 | ####router.param(name, callback)
1662 | 给路由参数添加回调触发器,这里的`name`是参数名,`function`是回调方法。回调方法的参数按序是请求对象,响应对象,下个中间件,参数值和参数名。虽然`name`在技术上是可选的,但是自Express V4.11.0之后版本不推荐使用(见下面)。
1663 | > 不像`app.param()`,`router.param()`不接受一个数组作为路由参数。
1664 |
1665 | 例如,当`:user`出现在路由路径中,你可以映射用户加载的逻辑处理来自动提供`req.user`给这个路由,或者对输入的参数进行验证。
1666 | ```js
1667 | router.param('user', function(req, res, next, id) {
1668 | User.find(id, function(error, user) {
1669 | if (err) {
1670 | next(err);
1671 | }
1672 | else if (user){
1673 | req.user = user;
1674 | } else {
1675 | next(new Error('failed to load user'));
1676 | }
1677 | });
1678 | });
1679 | ```
1680 | 对于`Param`的回调定义的路由来说,他们是局部的。它们不会被挂载的app或者路由继承。所以,定义在`router`上的`param`回调只有是在`router`上的路由具有这个路由参数时才起作用。
1681 | 在定义`param`的路由上,`param`回调都是第一个被调用的,它们在一个请求-响应循环中都会被调用一次并且只有一次,即使多个路由都匹配,如下面的例子:
1682 | ```js
1683 | router.param('id', function(req, res, next, id) {
1684 | console.log('CALLED ONLY ONCE');
1685 | next();
1686 | });
1687 |
1688 | router.get('/user/:id', function(req, res, next) {
1689 | console.log('although this matches');
1690 | next();
1691 | });
1692 |
1693 | router.get('/user/:id', function(req, res) {
1694 | console.log('and this mathces too');
1695 | res.end();
1696 | });
1697 | ```
1698 | 当`GET /user/42`,得到下面的结果:
1699 | ```log
1700 | CALLED ONLY ONCE
1701 | although this matches
1702 | and this matches too
1703 | ```
1704 | `
1705 |
1706 | >下面章节描述的`router.param(callback)`在v4.11.0之后被弃用。
1707 |
1708 | 通过只传递一个回调参数给`router.param(name, callback)`方法,`router.param(naem, callback)`方法的行为将被完全改变。这个回调参数是关于`router.param(name, callback)`该具有怎样的行为的一个自定义方法,这个方法必须接受两个参数并且返回一个中间件。
1709 | 这个回调的第一个参数就是需要捕获的url的参数名,第二个参数可以是任一的JavaScript对象,其可能在实现返回一个中间件时被使用。
1710 | 这个回调方法返回的中间件决定了当URL中包含这个参数时所采取的行为。
1711 | 在下面的例子中,`router.param(name, callback)`参数签名被修改成了`router.param(name, accessId)`。替换接受一个参数名和回调,`router.param()`现在接受一个参数名和一个数字。
1712 | ```js
1713 | var express = require('express');
1714 | var app = express();
1715 | var router = express.Router();
1716 |
1717 | router.param(function(param, option){
1718 | return function(req, res, next, val) {
1719 | if (val == option) {
1720 | next();
1721 | }
1722 | else {
1723 | res.sendStatus(403);
1724 | }
1725 | }
1726 | });
1727 |
1728 | router.param('id', 1337);
1729 |
1730 | router.get('/user/:id', function(req, res) {
1731 | res.send('Ok');
1732 | });
1733 |
1734 | app.use(router);
1735 |
1736 | app.listen(3000, function() {
1737 | console.log('Ready');
1738 | });
1739 | ```
1740 | 在这个例子中,`router.param(name. callback)`参数签名保持和原来一样,但是替换成了一个中间件,定义了一个自定义的数据类型检测方法来检测`user id`的类型正确性。
1741 | ```js
1742 | router.param(function(param, validator) {
1743 | return function(req, res, next, val) {
1744 | if (validator(val)) {
1745 | next();
1746 | }
1747 | else {
1748 | res.sendStatus(403);
1749 | }
1750 | }
1751 | });
1752 |
1753 | router.param('id', function(candidate) {
1754 | return !isNaN(parseFloat(candidate)) && isFinite(candidate);
1755 | });
1756 | ```
1757 | ####router.route(path)
1758 | 返回一个单例模式的路由的实例,之后你可以在其上施加各种HTTP动作的中间件。使用`app.route()`来避免重复路由名字(因此错字错误)--后面这句不知道说的什么鬼,大概的意思就是避免同一个路径有两个路由实例。
1759 | 构建在上面的`router.param()`例子之上,下面的代码展示了怎么使用`router.route()`来指定各种HTTP方法的处理句柄。
1760 | ```js
1761 | var router = express.Router();
1762 |
1763 | router.param('user_id', function(req, res, next, id) {
1764 | // sample user, would actually fetch from DB, etc...
1765 | req.user = {
1766 | id:id,
1767 | name:"TJ"
1768 | };
1769 | next();
1770 | });
1771 |
1772 | router.route('/users/:user_id')
1773 | .all(function(req, res, next) {
1774 | // runs for all HTTP verbs first
1775 | // think of it as route specific middleware!
1776 | next();
1777 | })
1778 | .get(function(req, res, next) {
1779 | res.json(req.user);
1780 | })
1781 | .put(function(req, res, next) {
1782 | // just an example of maybe updating the user
1783 | req.user.name = req.params.name;
1784 | // save user ... etc
1785 | res.json(req.user);
1786 | })
1787 | .post(function(req, res, next) {
1788 | next(new Error('not implemented'));
1789 | })
1790 | .delete(function(req, res, next) {
1791 | next(new Error('not implemented'));
1792 | })
1793 | ```
1794 | 这种方法重复使用单个`/usrs/:user_id`路径来添加了各种的HTTP方法。
1795 |
1796 | ####router.use([path], [function, ...] function)
1797 | 给可选的`path`参数指定的路径挂载给定的中间件方法,未指定`path`参数,默认值为`/`。
1798 | 这个方法类似于`app.use()`。一个简单的例子和用例在下面描述。查阅[app.use()][56]获得更多的信息。
1799 | 中间件就像一个水暖管道,请求在你定义的第一个中间件处开始,顺着中间件堆栈一路往下,如果路径匹配则处理这个请求。
1800 | ```js
1801 | var express = require('express');
1802 | var app = express();
1803 | var router = express.Router();
1804 |
1805 |
1806 | // simple logger for this router`s requests
1807 | // all requests to this router will first hit this middleware
1808 |
1809 | router.use(function(req, res, next) {
1810 | console.log('%s %s %s', req.method, req.url, req.path);
1811 | next();
1812 | })
1813 |
1814 | // this will only be invoked if the path starts with /bar form the mount ponit
1815 | router.use('/bar', function(req, res, next) {
1816 | // ... maybe some additional /bar logging ...
1817 | next();
1818 | })
1819 |
1820 | // always be invoked
1821 | router.use(function(req, res, next) {
1822 | res.send('hello world');
1823 | })
1824 |
1825 | app.use('/foo', router);
1826 |
1827 | app.listen(3000);
1828 |
1829 | ```
1830 | 对于中间件`function`,挂载的路径是被剥离的和不可见的。关于这个特性主要的影响是对于不同的路径,挂载相同的中间件可能对代码不做改动,尽管其前缀已经改变。
1831 | 你使用`router.use()`定义中间件的顺序很重要。中间们是按序被调用的,所以顺序决定了中间件的优先级。例如,通常日志是你将使用的第一个中间件,以便每一个请求都被记录。
1832 | ```js
1833 | var logger = require('morgan');
1834 |
1835 | router.use(logger());
1836 | router.use(express.static(__dirname + '/public'));
1837 | router.use(function(req, res) {
1838 | res.send('Hello');
1839 | });
1840 | ```
1841 | 现在为了支持你不希望记录静态文件请求,但为了继续记录那些定义在`logger()`之后的路由和中间件。你可以简单的将`static()`移动到前面来解决:
1842 | ```js
1843 | router.use(express.static(__dirname + '/public'));
1844 | router.use(logger());
1845 | router.use(function(req, res){
1846 | res.send('Hello');
1847 | });
1848 | ```
1849 | 另外一个确凿的例子是从不同的路径托管静态文件,你可以将`./public`放到前面来获得更高的优先级:
1850 | ```js
1851 | app.use(express.static(__dirname + '/public'));
1852 | app.use(express.static(__dirname + '/files'));
1853 | app.use(express.static(__dirname + '/uploads'));
1854 | ```
1855 | `router.use()`方法也支持命名参数,以便你的挂载点对于其他的路由而言,可以使用命名参数来进行预加载,这样做是很有益的。
1856 |
1857 |
1858 |
1859 |
1860 |
1861 |
1862 |
1863 |
1864 |
1865 |
1866 |
1867 | [1]: https://github.com/expressjs/serve-static?_ga=1.1179825.1201680737.1446005628
1868 | [2]: https://www.npmjs.org/package/ms
1869 | [3]: http://expressjs.com/starter/static-files.html
1870 | [4]: http://expressjs.com/4x/api.html#app.METHOD
1871 | [5]: http://expressjs.com/4x/api.html#app.param
1872 | [6]: http://expressjs.com/4x/api.html#app.route
1873 | [7]: http://expressjs.com/4x/api.html#app.render
1874 | [8]: http://expressjs.com/4x/api.html#app.engine
1875 | [9]: http://expressjs.com/4x/api.html#app.settings.table
1876 | [10]: http://expressjs.com/4x/api.html#req.app
1877 | [11]: http://expressjs.com/4x/api.html#req.baseUrl
1878 | [12]: http://expressjs.com/guide/routing.html
1879 | [13]: http://expressjs.com/4x/api.html#app.settings.table
1880 | [14]: http://expressjs.com/4x/api.html#app.settings.table
1881 | [15]: http://expressjs.com/4x/api.html#app.settings.table
1882 | [16]: http://expressjs.com/4x/api.html#app.settings.table
1883 | [17]: https://github.com/tj/consolidate.js?_ga=1.260760333.1201680737.1446005628
1884 | [18]: http://expressjs.com/4x/api.html#app.settings.table
1885 | [19]: http://expressjs.com/guide/routing.html
1886 | [20]: http://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback
1887 | [21]: http://expressjs.com/guide/routing.html
1888 | [22]: http://expressjs.com/guide/routing.html
1889 | [23]: http://expressjs.com/guide/routing.html
1890 | [24]: http://expressjs.com/4x/api.html#app.settings.table
1891 | [25]: http://expressjs.com/4x/api.html#etag.options.table
1892 | [26]: http://en.wikipedia.org/wiki/HTTP_ETag
1893 | [27]: http://nodejs.org/api/querystring.html
1894 | [28]: http://expressjs.com/4x/api.html#trust.proxy.options.table
1895 | [29]: http://expressjs.com/guide/behind-proxies.html
1896 | [30]: https://www.npmjs.org/package/etag
1897 | [31]: http://expressjs.com/guide/using-middleware.html
1898 | [32]: http://expressjs.com/4x/api.html#app.mountpath
1899 | [33]: https://github.com/expressjs/cookie-parser?_ga=1.268562033.1201680737.1446005628
1900 | [34]: https://nodejs.org/api/http.html#http_message_url
1901 | [35]: http://expressjs.com/4x/api.html#app.use
1902 | [36]: https://github.com/expressjs/cookie-parser?_ga=1.25372221.1201680737.1446005628
1903 | [37]: http://expressjs.com/4x/api.html#req.fresh
1904 | [38]: https://github.com/expressjs/accepts?_ga=1.88139675.1201680737.1446005628
1905 | [39]: https://github.com/expressjs/accepts?_ga=1.88139675.1201680737.1446005628
1906 | [40]: https://github.com/expressjs/accepts?_ga=1.88139675.1201680737.1446005628
1907 | [41]: https://github.com/expressjs/accepts?_ga=1.88139675.1201680737.1446005628
1908 | [42]: https://github.com/expressjs/type-is?_ga=1.33770401.1201680737.1446005628
1909 | [43]: http://expressjs.com/4x/api.html#req.body
1910 | [44]: https://nodejs.org/api/http.html#http_response_end_data_encoding_callback
1911 | [45]: http://expressjs.com/4x/api.html#res.send
1912 | [46]: http://expressjs.com/4x/api.html#res.json
1913 | [47]: http://expressjs.com/4x/api.html#req.accepts
1914 | [48]: http://expressjs.com/4x/api.html#app.settings.table
1915 | [49]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
1916 | [50]: http://en.wikipedia.org/wiki/HTTP_referer
1917 | [51]: https://www.npmjs.org/package/ms
1918 | [52]: https://github.com/pillarjs/send?_ga=1.256986891.1201680737.1446005628
1919 | [53]: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
1920 | [54]: http://nodejs.org/api/http.html#http_response_statuscode
1921 | [55]: https://github.com/broofa/node-mime?_ga=1.67301009.1201680737.1446005628#mimelookuppath
1922 | [56]: http://expressjs.com/en/4x/api.html#app.use
1923 |
--------------------------------------------------------------------------------