express()
創建一個express應用程序
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
app.listen(3000);
Application
將設置項 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 專門把所有的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定義了下面的回調,這個允許你使用一個給定的正則去限制參數。
下面的這個例子有一點點高級,檢查如果第二個參數是一個正則,返回一個很像上面的"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: '[email protected]'
});
app.locals.title
// => 'My App'
app.locals.email
// => '[email protected]'
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 規範 介紹了原來的屬性,有一些還會被現代的JS引擎識別,EcmaScript 規範 在它的基礎上,統一了值,添加了一些,刪除了一些廢棄的。如果感興趣,可以看看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()定義的情況下用它來處理默認的OPTIONS行爲。 你的應用程序或者框架也可以很輕鬆的通過在這個對象裏移除路由來達到刪除路由的目的。
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()是一致的
var express = require('express');
var app = express();
app.listen(3000);
express()返回的app實際上是一個JavaScriptFunction,它被設計爲傳給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
這是一個數組對象,命名過的參數會以鍵值對的形式存放。 比如你有一個路由/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][email protected]
req.body.user.name
// => "tobi"
req.body.user.email
// => "[email protected]"
// 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來處理文件請求,所以接收的參數是一致的。 舉個例子,使用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()的掛載功能會重寫 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
支持鏈式調用的 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 對象訪問到這個值。
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來修改這個值。 下面是一些使用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.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.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
基本的認證中間件,在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());
如果你的應用程序需要使用文件上傳,設置一下就行。 一個簡單的介紹如何使用.
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.