# API 參考
### express()
創建一個express應用程序
```
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
app.listen(3000);
```
## Application
<a name="application"></a>
### app.set(name, value)
將設置項 `name` 的值設為 `value`
```
app.set('title', 'My Site');
app.get('title');
// => "My Site"
```
### app.get(name)
獲取設置項 `name` 的值
```
app.get('title');
// => undefined
app.set('title', 'My Site');
app.get('title');
// => "My Site"
```
### app.enable(name)
將設置項 `name` 的值設為 `true`.
```
app.enable('trust proxy');
app.get('trust proxy');
// => true
```
### app.disable(name)
將設置項 `name` 的值設為 `false`.
```
app.disable('trust proxy');
app.get('trust proxy');
// => false
```
### app.enabled(name)
檢查設置項 `name` 是否已啟用
```
app.enabled('trust proxy');
// => false
app.enable('trust proxy');
app.enabled('trust proxy');
// => true
```
### app.disabled(name)
檢查設置項 `name` 是否已禁用
```
app.disabled('trust proxy');
// => true
app.enable('trust proxy');
app.disabled('trust proxy');
// => false
```
### app.configure([env], callback)
當 `env` 和 `app.get('env')`(也就是 `process.env.NODE_ENV`) 匹配時, 調用`callback`。保留這個方法是出于歷史原因,后面列出的`if`語句的代碼其實更加高效、直接。使用`app.set()`配合其它一些配置方法后,_沒有_必要再使用這個方法。
```
// 所有環境
app.configure(function(){
app.set('title', 'My Application');
})
// 開發環境
app.configure('development', function(){
app.set('db uri', 'localhost/dev');
})
// 只用于生產環境
app.configure('production', function(){
app.set('db uri', 'n.n.n.n/prod');
})
```
更高效且直接的代碼如下:
```
// 所有環境
app.set('title', 'My Application');
// 只用于開發環境
if ('development' == app.get('env')) {
app.set('db uri', 'localhost/dev');
}
// 只用于生產環境
if ('production' == app.get('env')) {
app.set('db uri', 'n.n.n.n/prod');
}
```
### app.use([path], function)
使用中間件 `function`,可選參數`path`默認為"/"。
```
var express = require('express');
var app = express();
// 一個簡單的 logger
app.use(function(req, res, next){
console.log('%s %s', req.method, req.url);
next();
});
// 響應
app.use(function(req, res, next){
res.send('Hello World');
});
app.listen(3000);
```
掛載的路徑不會在req里出現,對中間件 `function`**不**可見,這意味著你在`function`的回調參數req里找不到path。 這么設計的為了讓間件可以在不需要更改代碼就在任意"前綴"路徑下執行
這里有一個實際應用場景,常見的一個應用是使用./public提供靜態文件服務, 用 `express.static()` 中間件:
```
// GET /javascripts/jquery.js
// GET /style.css
// GET /favicon.ico
app.use(express.static(__dirname + '/public'));
```
如果你想把所有的靜態文件路徑都前綴"/static", 你可以使用“掛載”功能。 如果`req.url` 不包含這個前綴, 掛載過的中間件**不會**執行。 當`function`被執行的時候,這個參數不會被傳遞。 這個只會影響這個函數,后面的中間件里得到的 `req.url`里將會包含"/static"
```
// GET /static/javascripts/jquery.js
// GET /static/style.css
// GET /static/favicon.ico
app.use('/static', express.static(__dirname + '/public'));
```
使用 `app.use()` “定義的”中間件的順序非常重要,它們將會順序執行,use的先后順序決定了中間件的優先級。 比如說通常 `express.logger()` 是最先使用的一個組件,紀錄每一個請求
```
app.use(express.logger());
app.use(express.static(__dirname + '/public'));
app.use(function(req, res){
res.send('Hello');
});
```
如果你想忽略請求靜態文件的紀錄,但是對于在 `logger()`之后定義的路由和中間件想繼續紀錄,只需要簡單的把 `static()` 移到前面就行了:
```
app.use(express.static(__dirname + '/public'));
app.use(express.logger());
app.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'));
```
### settings
下面的內建的可以改變Express行為的設置
* `env` 運行時環境,默認為 `process.env.NODE_ENV` 或者 "development"
* `trust proxy` 激活反向代理,默認未激活狀態
* `jsonp callback name` 修改默認`?callback=`的jsonp回調的名字
* `json replacer` JSON replacer 替換時的回調, 默認為null
* `json spaces` JSON 響應的空格數量,開發環境下是`2` , 生產環境是`0`
* `case sensitive routing` 路由的大小寫敏感, 默認是關閉狀態, "/Foo" 和"/foo" 是一樣的
* `strict routing` 路由的嚴格格式, 默認情況下 "/foo" 和 "/foo/" 是被同樣對待的
* `view cache` 模板緩存,在生產環境中是默認開啟的
* `view engine` 模板引擎
* `views` 模板的目錄, 默認是"process.cwd() + ./views"
### app.engine(ext, callback)
注冊模板引擎的 `callback` 用來處理`ext`擴展名的文件 默認情況下, 根據文件擴展名`require()` 對應的模板引擎。 比如你想渲染一個 "foo.jade" 文件,Express會在內部執行下面的代碼,然后會緩存`require()`,這樣就可以提高后面操作的性能
```
app.engine('jade', require('jade').__express);
```
那些沒有提供 `.__express` 的或者你想渲染一個文件的擴展名與模板引擎默認的不一致的時候,也可以用這個方法。 比如你想用EJS模板引擎來處理 ".html" 后綴的文件:
```
app.engine('html', require('ejs').renderFile);
```
這個例子中EJS提供了一個`.renderFile()` 方法和Express預期的格式: `(path, options, callback)`一致, 可以在內部給這個方法取一個別名`ejs.__express`,這樣你就可以使用".ejs" 擴展而不需要做任何改動
有些模板引擎沒有遵循這種轉換, 這里有一個小項目[consolidate.js](https://github.com/visionmedia/consolidate.js) 專門把所有的node流行的模板引擎進行了包裝,這樣它們在Express內部看起來就一樣了。
```
var engines = require('consolidate');
app.engine('haml', engines.haml);
app.engine('html', engines.hogan);
```
### app.param([name], callback)
路由參數的處理邏輯。比如當 `:user` 出現在一個路由路徑中,你也許會自動載入加載用戶的邏輯,并把它放置到 `req.user` , 或者校驗一下輸入的參數是否正確。
下面的代碼片段展示了`callback`很像中間件,但是在參數里多加了一個值,這里名為`id`. 它會嘗試加載用戶信息,然后賦值給`req.user`, 否則就傳遞錯誤`next(err)`.
```
app.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('failed to load user'));
}
});
});
```
另外你也可以只傳一個`callback`, 這樣你就有機會改變 `app.param()` API. 比如[express-params](http://github.com/visionmedia/express-params)定義了下面的回調,這個允許你使用一個給定的正則去限制參數。
下面的這個例子有一點點高級,檢查如果第二個參數是一個正則,返回一個很像上面的"user"參數例子行為的回調函數。
```
app.param(function(name, fn){
if (fn instanceof RegExp) {
return function(req, res, next, val){
var captures;
if (captures = fn.exec(String(val))) {
req.params[name] = captures;
next();
} else {
next('route');
}
}
}
});
```
這個函數現在可以非常有效的用來校驗參數,或者提供正則捕獲后的分組。
```
app.param('id', /^\d+$/);
app.get('/user/:id', function(req, res){
res.send('user ' + req.params.id);
});
app.param('range', /^(\w+)\.\.(\w+)?$/);
app.get('/range/:range', function(req, res){
var range = req.params.range;
res.send('from ' + range[1] + ' to ' + range[2]);
});
```
### app.VERB(path, [callback...], callback)
`app.VERB()` 方法為Express提供路由方法, **VERB** 是指某一個HTTP 動作, 比如 `app.post()`。 可以提供多個callbacks,這多個callbacks都將會被平等對待 ,它們的行為跟中間件一樣,也有一個例外的情況,如果某一個callback執行了`next('route')`,它后面的callback就被忽略。這種情形會應用在當滿足一個路由前綴,但是不需要處理這個路由,于是把它向后傳遞。
下面的代碼片段展示最簡單的路由定義。Express 會把路徑字符串轉為正則表達式,然后在符合規則的請求到達時立即使用。 請求參數_不會_ 被考慮進來,比如 "GET /" 會匹配下面的這個路由, 而"GET /?name=tobi"同樣也會匹配。
```
app.get('/', function(req, res){
res.send('hello world');
});
```
同樣也可以使用正則表達式,并且它能夠在你指定特定路徑的時候發揮大作用。 比如下面的例子可以匹配"GET /commits/71dbb9c" , 同時也能匹配 "GET /commits/71dbb9c..4c084f9".
```
app.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){
var from = req.params[0];
var to = req.params[1] || 'HEAD';
res.send('commit range ' + from + '..' + to);
});
```
可以傳遞一些回調,這對復用一些加載資源、校驗的中間件很有用。
```
app.get('/user/:id', user.load, function(){
// ...
})
```
這些回調同樣可以通過數組傳遞,簡單的放置在數組中即可。
```
var middleware = [loadForum, loadThread];
app.get('/forum/:fid/thread/:tid', middleware, function(){
// ...
})
app.post('/forum/:fid/thread/:tid', middleware, function(){
// ...
})
```
### app.all(path, [callback...], callback)
這個方法很像`app.VERB()` , 但是它匹配所有的HTTP動作
這個方法在給特定前綴路徑或者任意路徑上處理時會特別有用。 比如你想把下面的路由放在所有其它路由之前,它需要所有從這個路由開始的加載驗證,并且自動加載一個用戶 記住所有的回調都不應該被當作終點, `loadUser` 能夠被當作一個任務,然后`next()`去匹配接下來的路由。
```
app.all('*', requireAuthentication, loadUser);
```
Or the equivalent:
```
app.all('*', requireAuthentication)
app.all('*', loadUser);
```
另一個非常贊的例子是全局白名單函數。這里有一個例子跟前一個很像,但是它限制前綴為"/api":
```
app.all('/api/*', requireAuthentication);
```
### app.locals
應用程序本地變量會附加給所有的在這個應用程序內渲染的模板。 這是一個非常有用的模板函數,就像應用程序級數據一樣。
```
app.locals.title = 'My App';
app.locals.strftime = require('strftime');
```
`app.locals` 對象是一個JavaScript `Function`, 執行的時候它會把屬性合并到它自身,提供了一種簡單展示已有對象作為本地變量的方法
```
app.locals({
title: 'My App',
phone: '1-250-858-9990',
email: 'me@myapp.com'
});
app.locals.title
// => 'My App'
app.locals.email
// => 'me@myapp.com'
```
`app.locals`對象最終會是一個JavaScript函數對象,你不可以使用Functions和Objects內置的屬性,比如`name, apply, bind, call, arguments, length, constructor`
```
app.locals({name: 'My App'});
app.locals.name
// => 返回 'app.locals' 而不是 'My App' (app.locals 是一個函數 !)
// => 如果name變量用在一個模板里,發返回一個 ReferenceError
```
全部的保留字列表可以在很多規范里找到。 [JavaScript 規范](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) 介紹了原來的屬性,有一些還會被現代的JS引擎識別,[EcmaScript 規范](http://www.ecma-international.org/ecma-262/5.1/) 在它的基礎上,統一了值,添加了一些,刪除了一些廢棄的。如果感興趣,可以看看Functions和Objects的屬性值。
默認情況下Express只有一個應用程序級本地變量,它是 `settings`.
```
app.set('title', 'My App');
// 在view里使用 settings.title
```
### app.render(view, [options], callback)
渲染 `view`, `callback` 用來處理返回的渲染后的字符串。 這個是 `res.render()` 的應用程序級版本,它們的行為是一樣的。
```
app.render('email', function(err, html){
// ...
});
app.render('email', { name: 'Tobi' }, function(err, html){
// ...
});
```
### app.routes
`app.routes` 對象存儲了所有的被HTTP verb定義路由。 這個對象可以用在一些內部功能上,比如Express不僅用它來做路由分發,同時在沒有`app.options()`定義的情況下用它來處理默認的<string>OPTIONS</string>行為。 你的應用程序或者框架也可以很輕松的通過在這個對象里移除路由來達到刪除路由的目的。
```
console.log(app.routes)
{ get:
[ { path: '/',
method: 'get',
callbacks: [Object],
keys: [],
regexp: /^\/\/?$/i },
{ path: '/user/:id',
method: 'get',
callbacks: [Object],
keys: [{ name: 'id', optional: false }],
regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ],
delete:
[ { path: '/user/:id',
method: 'delete',
callbacks: [Object],
keys: [Object],
regexp: /^\/user\/(?:([^\/]+?))\/?$/i } ] }
```
### app.listen()
在給定的主機和端口上監聽請求,這個和node的文檔[http.Server#listen()](http://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback)是一致的
```
var express = require('express');
var app = express();
app.listen(3000);
```
`express()`返回的`app`實際上是一個JavaScript`Function`,它被設計為傳給node的http servers作為處理請求的回調函數。因為`app`不是從HTTP或者HTTPS繼承來的,它只是一個簡單的回調函數,你可以以同一份代碼同時處理HTTP and HTTPS 版本的服務。
```
var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
```
`app.listen()` 方法只是一個快捷方法,如果你想使用HTTPS,或者同時提供HTTP和HTTPS,可以使用上面的代碼
```
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
```
## Request
<a name="request"></a>
### req.params
這是一個數組對象,命名過的參數會以鍵值對的形式存放。 比如你有一個路由`/user/:name`, "name"屬性會存放在`req.params.name`. 這個對象默認為 `{}`.
```
// GET /user/tj
req.params.name
// => "tj"
```
當使用正則表達式定義路由的時候,`req.params[N]`會是這個應用這個正則后的捕獲分組, `N` 是代表的是第N個捕獲分組。這個規則同樣適用于全匹配的路由,如 `/file/*`:
```
// GET /file/javascripts/jquery.js
req.params[0]
// => "javascripts/jquery.js"
```
### req.query
這是一個解析過的請求參數對象,默認為`{}`.
```
// GET /search?q=tobi+ferret
req.query.q
// => "tobi ferret"
// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
req.query.order
// => "desc"
req.query.shoe.color
// => "blue"
req.query.shoe.type
// => "converse"
```
### req.body
這個對應的是解析過的請求體。這個特性是`bodyParser()` 中間件提供,其它的請求體解析中間件可以放在這個中間件之后。當`bodyParser()`中間件使用后,這個對象默認為 `{}`。
```
// POST user[name]=tobi&user[email]=tobi@learnboost.com
req.body.user.name
// => "tobi"
req.body.user.email
// => "tobi@learnboost.com"
// POST { "name": "tobi" }
req.body.name
// => "tobi"
```
### req.files
這是上傳的文件的對象。這個特性是`bodyParser()` 中間件提供,其它的請求體解析中間件可以放在這個中間件之后。當`bodyParser()`中間件使用后,這個對象默認為 `{}`。
例如 **file** 字段被命名為"image", 當一個文件上傳完成后,`req.files.image` 將會包含下面的 `File` 對象:
```
{ size: 74643,
path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876',
name: 'edge.png',
type: 'image/png',
hash: false,
lastModifiedDate: Thu Aug 09 2012 20:07:51 GMT-0700 (PDT),
_writeStream:
{ path: '/tmp/8ef9c52abe857867fd0a4e9a819d1876',
fd: 13,
writable: false,
flags: 'w',
encoding: 'binary',
mode: 438,
bytesWritten: 74643,
busy: false,
_queue: [],
_open: [Function],
drainable: true },
length: [Getter],
filename: [Getter],
mime: [Getter] }
```
`bodyParser()` 中間件是在內部使用[node-formidable](https://github.com/felixge/node-formidable)來處理文件請求,所以接收的參數是一致的。 舉個例子,使用formidable的選項`keepExtensions` , 它默認為 **false** , 在上面的例子可以看到給出的文件名"/tmp/8ef9c52abe857867fd0a4e9a819d1876" 不包含".png" 擴展名. 為了讓它可以保留擴展名,你可以把參數傳給 `bodyParser()`:
```
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/my/files' }));
```
### req.param(name)
返回 `name` 參數的值。
```
// ?name=tobi
req.param('name')
// => "tobi"
// POST name=tobi
req.param('name')
// => "tobi"
// /user/tobi for /user/:name
req.param('name')
// => "tobi"
```
查找的優先級如下:
* `req.params`
* `req.body`
* `req.query`
直接訪問 `req.body`, `req.params`, 和 `req.query` 應該更合適,除非你真的需要從這幾個對象里同時接受輸入。
### req.route
這個對象里是當前匹配的 `Route` 里包含的屬性,比如原始路徑字符串,產生的正則,等等
```
app.get('/user/:id?', function(req, res){
console.log(req.route);
});
```
上面代碼的一個輸出:
```
{ path: '/user/:id?',
method: 'get',
callbacks: [ [Function] ],
keys: [ { name: 'id', optional: true } ],
regexp: /^\/user(?:\/([^\/]+?))?\/?$/i,
params: [ id: '12' ] }
```
### req.cookies
當使用 `cookieParser()`中間件之后,這個對象默認為`{}`, 它也包含了用戶代理傳過來的cookies。
```
// Cookie: name=tj
req.cookies.name
// => "tj"
```
### req.signedCookies
當使用了`cookieParser(secret)` 中間件后,這個對象默認為`{}`, 否則包含了用戶代理傳回來的簽名后的cookie,并等待使用。簽名后的cookies被放在一個單獨的對象里,惡意攻擊者可以很簡單的替換掉`req.cookie` 的值。需要注意的是簽名的cookie不代表它是隱藏的或者加密的,這個只是簡單的阻止篡改cookie。
```
// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
req.signedCookies.user
// => "tobi"
```
### req.get(field)
獲取請求頭里的`field`的值,大小寫不敏感. _Referrer_ 和 _Referer_ 字段是可以互換的。
```
req.get('Content-Type');
// => "text/plain"
req.get('content-type');
// => "text/plain"
req.get('Something');
// => undefined
```
別名為 `req.header(field)`.
### req.accepts(types)
. 檢查給定的`types` 是不是可以接受類型,當可以接受時返回最匹配的,否則返回`undefined` - 這個時候你應該響應一個406 "Not Acceptable".
`type` 的值可能是單一的一個mime類型字符串,比如 "application/json", 擴展名為"json", 也可以為逗號分隔的列表或者數組。當給定的是數組或者列表,返回_最佳_匹配的。
```
// Accept: text/html
req.accepts('html');
// => "html"
// Accept: text/*, application/json
req.accepts('html');
// => "html"
req.accepts('text/html');
// => "text/html"
req.accepts('json, text');
// => "json"
req.accepts('application/json');
// => "application/json"
// Accept: text/*, application/json
req.accepts('image/png');
req.accepts('png');
// => undefined
// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json']);
req.accepts('html, json');
// => "json"
```
### req.accepted
返回一個從高質量到低質量排序的接受媒體類型數組
```
[ { value: 'application/json',
quality: 1,
type: 'application',
subtype: 'json' },
{ value: 'text/html',
quality: 0.5,
type: 'text',
subtype: 'html' } ]
```
### req.is(type)
檢查請求的文件頭是不是包含"Content-Type" 字段, 它匹配給定的`type`.
```
// With Content-Type: text/html; charset=utf-8
req.is('html');
req.is('text/html');
req.is('text/*');
// => true
// When Content-Type is application/json
req.is('json');
req.is('application/json');
req.is('application/*');
// => true
req.is('html');
// => false
```
### req.ip
返回遠程地址,或者當“信任代理”使用時,返回上一級的地址
```
req.ip
// => "127.0.0.1"
```
### req.ips
當設置"trust proxy" 為 `true`時, 解析"X-Forwarded-For" 里的ip地址列表,并返回一個數組 否則返回一個空數組 舉個例子,如果"X-Forwarded-For" 的值為"client, proxy1, proxy2" 你將會得到數組`["client", "proxy1", "proxy2"]` 這里可以看到 "proxy2" 是最近一個使用的代理
### req.path
返回請求的URL的路徑名
```
// example.com/users?sort=desc
req.path
// => "/users"
```
### req.host
返回從"Host"請求頭里取的主機名,不包含端口號。
```
// Host: "example.com:3000"
req.host
// => "example.com"
```
### req.fresh
判斷請求是不是新的-通過對Last-Modified 或者 ETag 進行匹配, 來標明這個資源是不是"新的".
```
req.fresh
// => true
```
### req.stale
判斷請求是不是舊的-如果Last-Modified 或者 ETag 不匹配, 標明這個資源是"舊的". Check if the request is stale - aka Last-Modified and/or the ETag do not match, indicating that the resource is "stale".
```
req.stale
// => true
```
### req.xhr
判斷請求頭里是否有"X-Requested-With"這樣的字段并且值為"XMLHttpRequest", jQuery等庫發請求時會設置這個頭
```
req.xhr
// => true
```
### req.protocol
返回標識請求協議的字符串,一般是"http",當用TLS請求的時候是"https"。 當"trust proxy" 設置被激活, "X-Forwarded-Proto" 頭部字段會被信任。 如果你使用了一個支持https的反向代理,那這個可能是激活的。
```
req.protocol
// => "http"
```
### req.secure
檢查TLS 連接是否已經建立。 這是下面的縮寫:
```
'https' == req.protocol;
```
### req.subdomains
把子域當作一個數組返回
```
// Host: "tobi.ferrets.example.com"
req.subdomains
// => ["ferrets", "tobi"]
```
### req.originalUrl
這個屬性很像 `req.url`, 但是它保留了原始的url。 這樣你在做內部路由的時候可以重寫`req.url`。 比如[app.use()](#app.use)的掛載功能會重寫 `req.url`,把從它掛載的點開始
```
// GET /search?q=something
req.originalUrl
// => "/search?q=something"
```
### req.acceptedLanguages
返回一個從高質量到低質量排序的接受語言數組
```
Accept-Language: en;q=.5, en-us
// => ['en-us', 'en']
```
### req.acceptedCharsets
返回一個從高質量到低質量排序的可接受的字符集數組
```
Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
// => ['unicode-1-1', 'iso-8859-5']
```
### req.acceptsCharset(charset)
檢查給定的`charset` 是不是可以接受的
### req.acceptsLanguage(lang)
檢查給定的 `lang` 是不是可以接受的
## Response
<a name="response"></a>
### res.status(code)
支持鏈式調用的 node's `res.statusCode=`.
```
res.status(404).sendfile('path/to/404.png');
```
### res.set(field, [value])
設置響應頭字段`field` 值為 `value`, 也可以一次傳入一個對象設置多個值。
```
res.set('Content-Type', 'text/plain');
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
})
```
`res.header(field, [value])`的別名。
### res.get(field)
返回一個大小寫不敏感的響應頭里的 `field`的值
```
res.get('Content-Type');
// => "text/plain"
```
### res.cookie(name, value, [options])
設置cookie `name` 值為`value`, 接受字符串參數或者JSON對象。 `path` 屬性默認為 "/".
```
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true });
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
```
`maxAge` 屬性是一個便利的設置"expires",它是一個從當前時間算起的毫秒。 下面的代碼和上一個例子中的第二行是同樣的作用。
```
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
```
可以傳一個序列化的JSON對象作為參數, 它會自動被`bodyParser()` 中間件解析。
```
res.cookie('cart', { items: [1,2,3] });
res.cookie('cart', { items: [1,2,3] }, { maxAge: 900000 });
```
這個方法也支持簽名的cookies。 只需要簡單的傳遞`signed` 參數。 `res.cookie()` 會使用通過 `express.cookieParser(secret)` 傳 入的secret來簽名這個值
```
res.cookie('name', 'tobi', { signed: true });
```
稍后你就可以通過[req.signedCookie](#req.signedCookies) 對象訪問到這個值。
### res.clearCookie(name, [options])
把`name`的cookie清除. `path`參數默認為 "/".
```
res.cookie('name', 'tobi', { path: '/admin' });
res.clearCookie('name', { path: '/admin' });
```
### res.redirect([status], url)
使用可選的狀態碼跳轉到`url` 狀態碼`status`默認為302 "Found".
```
res.redirect('/foo/bar');
res.redirect('http://example.com');
res.redirect(301, 'http://example.com');
res.redirect('../login');
```
Express支持幾種跳轉,第一種便是使用一個完整的URI跳轉到一個完全不同的網站。
```
res.redirect('http://google.com');
```
第二種是相對根域路徑跳轉,比如你現在在 `http://example.com/admin/post/new`, 下面的的代碼跳轉到 `/admin` 將會把你帶到`http://example.com/admin`:
```
res.redirect('/admin');
```
這是一種相對于應用程序掛載點的跳轉。 比如把一個blog程序掛在 `/blog`, 事實上它無法知道它被掛載,所以當你使用跳轉 `/admin/post/new` 時,將到跳到`http://example.com/admin/post/new`, 下面的相對于掛載點的跳轉會把你帶到 `http://example.com/blog/admin/post/new`:
```
res.redirect('admin/post/new');
```
路徑名.跳轉同樣也是支持的。 比如你在`http://example.com/admin/post/new`, 下面的跳轉會把你帶到 `http//example.com/admin/post`:
```
res.redirect('..');
```
最后也是最特別的跳轉是 `back` 跳轉, 它會把你帶回Referer(也有可能是Referrer)的地址 當Referer丟失的時候默認為 `/`
```
res.redirect('back');
```
### res.location
設置location 請求頭.
```
res.location('/foo/bar');
res.location('foo/bar');
res.location('http://example.com');
res.location('../login');
res.location('back');
```
可以使用與 `res.redirect()`里相同的`urls`。
舉個例子,如果你的程序根地址是`/blog`, 下面的代碼會把 `location` 請求頭設置為`/blog/admin`:
```
res.location('admin')
```
### res.charset
設置字符集。默認為"utf-8"。
```
res.charset = 'value';
res.send('some html');
// => Content-Type: text/html; charset=value
```
### res.send([body|status], [body])
發送一個響應。
```
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('some html');
res.send(404, 'Sorry, we cannot find that!');
res.send(500, { error: 'something blew up' });
res.send(200);
```
這個方法在輸出non-streaming響應的時候自動完成了大量有用的任務 比如如果在它前面沒有定義Content-Length, 它會自動設置; 比如加一些自動的 _HEAD_; 比如對HTTP緩存的支持 .
當參數為一個 `Buffer`時 Content-Type 會被設置為 "application/octet-stream" 除非它之前有像下面的代碼:
```
res.set('Content-Type', 'text/html');
res.send(new Buffer('some html'));
```
當參數為一個`String`時 Content-Type 默認設置為"text/html":
```
res.send('some html');
```
當參數為 `Array` 或者 `Object` 時 Express 會返回一個 JSON :
```
res.send({ user: 'tobi' })
res.send([1,2,3])
```
最后一條當一個`Number` 作為參數, 并且沒有上面提到的任何一條在響應體里, Express會幫你設置一個響應體 比如200 會返回字符"OK", 404會返回"Not Found"等等.
```
res.send(200)
res.send(204)
res.send(500)
```
### res.json([status|body], [body])
返回一個 JSON 響應。 當`res.send()` 的參數是一個對象或者數組的時候, 會調用這個方法。 當然它也在復雜的空值(null, undefined, etc)JSON轉換的時候很有用, 因為規范上這些對象不是合法的JSON。
```
res.json(null)
res.json({ user: 'tobi' })
res.json(500, { error: 'message' })
```
### res.jsonp([status|body], [body])
返回一個支持JSONP的JSON響應。 Send a JSON response with JSONP support. 這個方法同樣使用了`res.json()`, 只是加了一個可以自定義的 JSONP 回調支持。
```
res.jsonp(null)
// => null
res.jsonp({ user: 'tobi' })
// => { "user": "tobi" }
res.jsonp(500, { error: 'message' })
// => { "error": "message" }
```
默認情況下JSONP 回調的函數名就是`callback`。 你可以通過[jsonp callback name](#app-settings)來修改這個值。 下面是一些使用JSONP的例子。
```
// ?callback=foo
res.jsonp({ user: 'tobi' })
// => foo({ "user": "tobi" })
app.set('jsonp callback name', 'cb');
// ?cb=foo
res.jsonp(500, { error: 'message' })
// => foo({ "error": "message" })
```
### res.type(type)
設置 Sets the Content-Type to the mime lookup of `type`, or when "/" is present the Content-Type is simply set to this literal value.
```
res.type('.html');
res.type('html');
res.type('json');
res.type('application/json');
res.type('png');
```
`res.contentType(type)`方法的別名。
### res.format(object)
設置特定請求頭的響應。 這個方法使用 `req.accepted`, 這是一個通過質量值作為優先級順序的數組, 第一個回調會被執行。 當沒有匹配時,服務器返回一個 406 "Not Acceptable", 或者執行`default` 回調
Content-Type 在callback 被選中執行的時候會被設置好, 如果你想改變它,可以在callback內使用`res.set()`或者 `res.type()` 等
下面的例子展示了在請求頭設置為"application/json" 或者 "*/json"的時候 會返回`{ "message": "hey" }` 如果設置的是"*/*" 那么所有的返回都將是"hey"
```
res.format({
'text/plain': function(){
res.send('hey');
},
'text/html': function(){
res.send('hey');
},
'application/json': function(){
res.send({ message: 'hey' });
}
});
```
除了使用標準的MIME 類型,你也可以使用擴展名來映射這些類型 下面是一個不太完整的實現:
```
res.format({
text: function(){
res.send('hey');
},
html: function(){
res.send('hey');
},
json: function(){
res.send({ message: 'hey' });
}
});
```
### res.attachment([filename])
設置響應頭的Content-Disposition 字段值為 "attachment". 如果有`filename` 參數,Content-Type 將會依據文件擴展名通過`res.type()`自動設置, 并且Content-Disposition的"filename="參數將會被設置
```
res.attachment();
// Content-Disposition: attachment
res.attachment('path/to/logo.png');
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
```
### res.sendfile(path, [options], [fn]])
`path`所傳輸附件的路徑。
它會根據文件的擴展名自動設置響應頭里的Content-Type字段。 回調函數`fn(err)`在傳輸完成或者發生錯誤時會被調用執行。
Options:
* `maxAge` 毫秒,默認為0
* `root` 文件相對的路徑
這個方法可以非常良好的支持有縮略圖的文件服務。
```
app.get('/user/:uid/photos/:file', function(req, res){
var uid = req.params.uid
, file = req.params.file;
req.user.mayViewFilesFrom(uid, function(yes){
if (yes) {
res.sendfile('/uploads/' + uid + '/' + file);
} else {
res.send(403, 'Sorry! you cant see that.');
}
});
});
```
### res.download(path, [filename], [fn])
`path`所需傳輸附件的路徑, 通常情況下瀏覽器會彈出一個下載文件的窗口。 瀏覽器彈出框里的文件名和響應頭里的Disposition "filename=" 參數是一致的, 你也可以通過傳入`filename`來自由設置。
當在傳輸的過程中發生一個錯誤時,可選的回調函數`fn`會被調用執行。 這個方法使用[res.sendfile()](#res.sendfile)傳輸文件。
```
res.download('/report-12345.pdf');
res.download('/report-12345.pdf', 'report.pdf');
res.download('/report-12345.pdf', 'report.pdf', function(err){
if (err) {
// 處理錯誤,請牢記可能只有部分內容被傳輸,所以
// 檢查一下res.headerSent
} else {
// 減少下載的積分值之類的
}
});
```
### res.links(links)
合并給定的`links`, 并且設置給響應頭里的"Link" 字段.
```
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
});
```
轉換后:
```
Link: <http://api.example.com/users?page=2>; rel="next",
<http://api.example.com/users?page=5>; rel="last"
```
### res.locals
在某一次請求范圍下的響應體的本地變量,只對此次請求期間的views可見。 另外這個API其實和 [app.locals](#app.locals)是一樣的.
這個對象在放置請求級信息時非常有用,比如放置請求的路徑名,驗證過的用戶,用戶設置等等
```
app.use(function(req, res, next){
res.locals.user = req.user;
res.locals.authenticated = ! req.user.anonymous;
next();
});
```
### res.render(view, [locals], callback)
渲染`view`, 同時向callback 傳入渲染后的字符串。 callback如果不傳的話,直接會把渲染后的字符串輸出至請求方, 一般如果不需要再對渲染后的模板作操作,就不需要傳callback。 當有錯誤發生時`next(err)`會被執行. 如果提供了callback參數,可能發生的錯誤和渲染的字符串都會被當作參數傳入, 并且沒有默認響應。
```
res.render('index', function(err, html){
// ...
});
res.render('user', { name: 'Tobi' }, function(err, html){
// ...
});
```
## Middleware
<a name="middleware"></a>
### basicAuth()
基本的認證中間件,在`req.user`里添加用戶名
用戶名和密碼的例子:
```
app.use(express.basicAuth('username', 'password'));
```
校驗回調:
```
app.use(express.basicAuth(function(user, pass){
return 'tj' == user && 'wahoo' == pass;
}));
```
異步校驗接受參數`fn(err, user)`, 下面的例子`req.user` 將會作為user對象傳遞.
```
app.use(connect.basicAuth(function(user, pass, fn){
User.authenticate({ user: user, pass: pass }, fn);
}))
```
### bodyParser()
支持 JSON, urlencoded和multipart requests的請求體解析中間件。 這個中間件是`json()`, `urlencoded()`,和`multipart()` 這幾個中間件的簡單封裝
```
app.use(express.bodyParser());
// 等同于:
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());
```
從安全上考慮,如果你的應用程序不需要文件上傳功能,最好關閉它。我們只使用我們需要的中間件。例如:我們不使用`bodyParser`、`multipart()` 這兩個中間件。
```
app.use(express.json());
app.use(express.urlencoded());
```
如果你的應用程序需要使用文件上傳,設置一下就行。 [一個簡單的介紹如何使用](https://groups.google.com/d/msg/express-js/iP2VyhkypHo/5AXQiYN3RPcJ).
### compress()
通過gzip / deflate壓縮響應數據. 這個中間件應該放置在所有的中間件最前面以保證所有的返回都是被壓縮的
```
app.use(express.logger());
app.use(express.compress());
app.use(express.methodOverride());
app.use(express.bodyParser());
```
### cookieParser()
解析請求頭里的Cookie, 并用cookie名字的鍵值對形式放在 `req.cookies` 你也可以通過傳遞一個`secret` 字符串激活簽名了的cookie
```
app.use(express.cookieParser());
app.use(express.cookieParser('some secret'));
```
### cookieSession()
提供一個以cookie為基礎的sessions, 設置在`req.session`里。 這個中間件有以下幾個選項:
* `key` cookie 的名字,默認是 `connect.sess`
* `secret` prevents cookie tampering
* `cookie` session cookie 設置, 默認是 `{ path: '/', httpOnly: true, maxAge: null }`
* `proxy` 當設置安全cookies時信任反向代理 (通過 "x-forwarded-proto")
```
app.use(express.cookieSession());
```
清掉一個cookie, 只需要在響應前把null賦值給session:
```
req.session = null
```
### csrf()
CSRF 防護中間件
默認情況下這個中間件會產生一個名為"_csrf"的標志,這個標志應該添加到那些需要服務器更改的請求里,可以放在一個表單的隱藏域,請求參數等。這個標志可以通過 `req.csrfToken()`方法進行校驗。
`bodyParser()` 中間件產生的 `req.body` , `query()`產生的`req.query`,請求頭里的"X-CSRF-Token"是默認的 `value` 函數檢查的項
這個中間件需要session支持,因此它的代碼應該放在`session()`之后.
### directory()
文件夾服務中間件,用 `path` 提供服務。
```
app.use(express.directory('public'))
app.use(express.static('public'))
```
這個中間件接收如下參數:
* `hidden` 顯示隱藏文件,默認為false.
* `icons` 顯示圖標,默認為false.
* `filter` 在文件上應用這個過濾函數。默認為false.