https://www.runoob.com/w3cnote/express-4-x-api.html
原文地址:https://www.zybuluo.com/bajian/note/444152
Express 4.x API
express 翻譯 api文檔 中文
express()
express()用來創建一個Express的程序。express()方法是express模塊導出的頂層方法。
var express = require('express');var app = express();
Methods
express.static(root, [options])
express.static是Express中唯一的內建中間件。它以server-static模塊為基礎開發,負責托管 Express 應用內的靜態資源。
參數root為靜態資源的所在的根目錄。
參數options是可選的,支持以下的屬性:
| 屬性 | 描述 | 類型 | 默認值 |
|---|---|---|---|
| dotfiles | 是否響應點文件。供選擇的值有"allow","deny"和"ignore" | String | "ignore" |
| etag | 使能或者關閉etag | Boolean | true |
| extensions | 設置文件延期回退 | Boolean | true |
| index | 發送目錄索引文件。設置false將不發送。 | Mixed | "index.html" |
| lastModified | 設置文件在系統中的最后修改時間到Last-Modified頭部。可能的取值有false和true。 |
Boolean | true |
| maxAge | 在Cache-Control頭部中設置max-age屬性,精度為毫秒(ms)或則一段ms format的字符串 |
Number | 0 |
| redirect | 當請求的pathname是一個目錄的時候,重定向到尾隨"/" | Boolean | true |
| setHeaders | 當響應靜態文件請求時設置headers的方法 | Funtion |
如果你想獲得更多關於使用中間件的細節,你可以查閱Serving static files in Express。
Application()
app對象一般用來表示Express程序。通過調用Express模塊導出的頂層的express()方法來創建它:
var express = require('express');var app = express();app.get('/', function(req, res) {res.send('hello world!');});app.listen(3000);
app對象具有以下的方法:
- 路由HTTP請求;具體可以看app.METHOD和app.param這兩個例子。
- 配置中間件;具體請看app.route。
- 渲染HTML視圖;具體請看app.render。
- 注冊模板引擎;具體請看app.engine。
它還有一些屬性設置,這些屬性可以改變程序的行為。獲得更多的信息,可以查閱Application settings。
Properties
app.locals
app.locals對象是一個javascript對象,它的屬性就是程序本地的變量。
app.locals.title// => 'My App'app.locals.email// => 'me@myapp.com'
一旦設定,app.locals的各屬性值將貫穿程序的整個生命周期,與其相反的是res.locals,它只在這次請求的生命周期中有效。
在程序中,你可以在渲染模板時使用這些本地變量。它們是非常有用的,可以為模板提供一些有用的方法,以及app級別的數據。通過req.app.locals(具體查看req.app),Locals可以在中間件中使用。
app.locals.title = 'My App';app.locals.strftime = require('strftime');app.locals.email = 'me@myapp.com';
app.mountpath
app.mountpath屬性是子程序掛載的路徑模式。
一個子程序是一個
express的實例,其可以被用來作為路由句柄來處理請求。
var express = require('express');var app = express(); // the main appvar admin = express(); // the sub appadmin.get('/', function(req, res) {console.log(admin.mountpath); // /adminres.send('Admin Homepage');});app.use('/admin', admin); // mount the sub app
它和req對象的baseUrl屬性比較相似,除了req.baseUrl是匹配的URL路徑,而不是匹配的模式。如果一個子程序被掛載在多條路徑模式,app.mountpath就是一個關於掛載路徑模式項的列表,如下面例子所示。
```var admin = express();admin.get('/', function(req, res) {console.log(admin.mountpath); // ['adm*n', '/manager']res.send('Admin Homepage');});var secret = express();secret.get('/', function(req, res) {console.log(secret.mountpath); // /secr*tres.send('Admin secret');});admin.use('secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub appapp.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager' , on the parent app
Events
app.on('mount', callback(parent))
當子程序被掛載到父程序時,mount事件被發射。父程序對象作為參數,傳遞給回調方法。
var admin = express();admin.on('mount', function(parent) {console.log('Admin Mounted');console.log(parent); // refers to the parent app});admin.get('/', function(req, res) {res.send('Admin Homepage');});app.use('/admin', admin);
Methods
app.all(path, callback[, callback ...]
app.all方法和標准的app.METHOD()方法相似,除了它匹配所有的HTTP動詞。
對於給一個特殊前綴映射一個全局的邏輯處理,或者無條件匹配,它是很有效的。例如,如果你把下面內容放在所有其他的路由定義的前面,它要求所有從這個點開始的路由需要認證和自動加載一個用戶。記住這些回調並不是一定是終點:loadUser可以在完成了一個任務后,調用next()方法來繼續匹配隨后的路由。
app.all('*', requireAuthentication, loadUser);
或者這種相等的形式:
app.all('*', requireAuthentication);app.all('*', loadUser);
另一個例子是全局的白名單方法。這個例子和前面的很像,然而它只是限制以/api開頭的路徑。
app.all('/api/*', requireAuthentication);
app.delete(path, callback[, callback ...])
路由HTTP DELETE請求到有特殊回調方法的特殊的路徑。獲取更多的信息,可以查閱routing guide。
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果不能滿足當前路由的處理條件,那么你可以傳遞控制到隨后的路由。
app.delete('/', function(req, res) {res.send('DELETE request to homepage');});
app.disable(name)
設置類型為布爾的設置名為name的值為false,此處的name是app settings table中各屬性的一個。調用app.set('foo', false)和調用app.disable('foo')是等價的。
比如:
app.disable('trust proxy');app.get('trust proxy');// => false
app.disabled(name)
返回true如果布爾類型的設置值name被禁用為false,此處的name是app settings table中各屬性的一個。
app.disabled('trust proxy');// => trueapp.enable('trust proxy');app.disabled('trust proxy');// => false
app.enable(name)
設置布爾類型的設置值name為true,此處的name是app settings table中各屬性的一個。調用app.set('foo', true)和調用app.enable('foo')是等價的。
app.enable('trust proxy');app.get('trust proxy');// => true
app.enabled(name)
返回true如果布爾類型的設置值name被啟動為true,此處的name是app settings table中各屬性的一個。
app.enabled('trust proxy');// => falseapp.enable('trust proxy');app.enabled('trust proxy');// => true
app.engine(ext, callback)
注冊給定引擎的回調,用來渲染處理ext文件。
默認情況下,Express需要使用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庫映射模板引擎以下面的使用方式,所以他們可以無縫的和Express工作。
var engines = require('consolidate');app.engine('haml', engines.haml);app.engine('html', engines.hogan);
app.get(name)
獲得設置名為name的app設置的值,此處的name是app settings table中各屬性的一個。
如下:
app.get('title');// => undefinedapp.set('title', 'My Site');app.get('title');// => 'My Site'
app.get(path, callback [, callback ...])
路由HTTP GET請求到有特殊回調的特殊路徑。獲取更多的信息,可以查閱routing guide。
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果請求沒能滿足當前路由的處理條件,那么傳遞控制到隨后的路由。
app.get('/', function(req, res) {res.send('GET request to homepage');});
app.listen(port, [hostname], [backlog], [callback])
綁定程序監聽端口到指定的主機和端口號。這個方法和Node中的http.Server.listen()是一樣的。
var express = require('express');var app = express();app.listen(3000);
通過調用express()返回得到的app實際上是一個JavaScript的Function,被設計用來作為一個回調傳遞給Node HTTP servers來處理請求。這樣,其就可以很簡便的基於同一份代碼提供http和https版本,所以app沒有從這些繼承(它只是一個簡單的回調)。
var express = require('express');var https = require('https');var http = require('http');http.createServer(app).listen(80);https.createServer(options, app).listen(443);
app.listen()方法是下面所示的一個便利的方法(只針對HTTP協議):
app.listen = function() {var server = http.createServer(this);return server.listen.apply(server, arguments);};
app.METHOD(path, callback [, callback ...])
路由一個HTTP請求,METHOD是這個請求的HTTP方法,比如GET,PUT,POST等等,注意是小寫的。所以,實際的方法是app.get(),app.post(),app.put()等等。下面有關於方法的完整的表。
獲取更多信息,請看routing guide。
Express支持下面的路由方法,對應與同名的HTTP方法:
|
|
|
如果使用上述方法時,導致了無效的javascript的變量名,可以使用中括號符號,比如,
app['m-search']('/', function ...
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果請求沒有滿足當前路由的處理條件,那么傳遞控制到隨后的路由。
本API文檔把使用比較多的HTTP方法
app.get(),app.post,app.put(),app.delete()作為一個個單獨的項進行說明。然而,其他上述列出的方法以完全相同的方式工作。
app.all()是一個特殊的路由方法,它不屬於HTTP協議中的規定的方法。它為一個路徑加載中間件,其對所有的請求方法都有效。
app.all('/secret', function (req, res) {console.log('Accessing the secret section...');next(); // pass control to the next handler});
app.param([name], callback)
給路由參數添加回調觸發器,這里的name是參數名或者參數數組,function是回調方法。回調方法的參數按序是請求對象,響應對象,下個中間件,參數值和參數名。
如果name是數組,會按照各個參數在數組中被聲明的順序將回調觸發器注冊下來。還有,對於除了最后一個參數的其他參數,在他們的回調中調用next()來調用下個聲明參數的回調。對於最后一個參數,在回調中調用next()將調用位於當前處理路由中的下一個中間件,如果name只是一個string那就和它是一樣的(就是說只有一個參數,那么就是最后一個參數,和數組中最后一個參數是一樣的)。
例如,當:user出現在路由路徑中,你可以映射用戶加載的邏輯處理來自動提供req.user給這個路由,或者對輸入的參數進行驗證。
app.param('user', function(req, res, next, id) {User.find(id, function(error, user) {if (err) {next(err);}else if (user){req.user = user;} else {next(new Error('failed to load user'));}});});
對於Param的回調定義的路由來說,他們是局部的。它們不會被掛載的app或者路由繼承。所以,定義在app上的Param回調只有是在app上的路由具有這個路由參數時才起作用。
在定義param的路由上,param回調都是第一個被調用的,它們在一個請求-響應循環中都會被調用一次並且只有一次,即使多個路由都匹配,如下面的例子:
app.param('id', function(req, res, next, id) {console.log('CALLED ONLY ONCE');next();});app.get('/user/:id', function(req, res, next) {console.log('although this matches');next();});app.get('/user/:id', function(req, res) {console.log('and this mathces too');res.end();});
當GET /user/42,得到下面的結果:
CALLED ONLY ONCEalthough this matchesand this matches too
app.param(['id', 'page'], function(req, res, next, value) {console.log('CALLED ONLY ONCE with', value);next();});app.get('/user/:id/:page', function(req. res, next) {console.log('although this matches');next();});app.get('/user/:id/:page', function (req, res, next) {console.log('and this matches too');res.end();});
當執行GET /user/42/3,結果如下:
CALLED ONLY ONCE with 42CALLED ONLY ONCE with 3although this matchesand this mathes too
下面章節描述的
app.param(callback)在v4.11.0之后被棄用。
通過只傳遞一個回調參數給app.param(name, callback)方法,app.param(naem, callback)方法的行為將被完全改變。這個回調參數是關於app.param(name, callback)該具有怎樣的行為的一個自定義方法,這個方法必須接受兩個參數並且返回一個中間件。
這個回調的第一個參數就是需要捕獲的url的參數名,第二個參數可以是任一的JavaScript對象,其可能在實現返回一個中間件時被使用。
這個回調方法返回的中間件決定了當URL中包含這個參數時所采取的行為。
在下面的例子中,app.param(name, callback)參數簽名被修改成了app.param(name, accessId)。替換接受一個參數名和回調,app.param()現在接受一個參數名和一個數字。
var express = require('express');var app = express();app.param(function(param, option){return function(req, res, next, val) {if (val == option) {next();}else {res.sendStatus(403);}}});app.param('id', 1337);app.get('/user/:id', function(req, res) {res.send('Ok');});app.listen(3000, function() {console.log('Ready');});
在這個例子中,app.param(name, callback)參數簽名保持和原來一樣,但是替換成了一個中間件,定義了一個自定義的數據類型檢測方法來檢測user id的類型正確性。
app.param(function(param, validator) {return function(req, res, next, val) {if (validator(val)) {next();}else {res.sendStatus(403);}}});app.param('id', function(candidate) {return !isNaN(parseFloat(candidate)) && isFinite(candidate);});
在使用正則表達式來,不要使用
.。例如,你不能使用/user-.+/來捕獲user-gami,用使用[\\s\\S]或者[\\w\\>W]來代替(正如/user-[\\s\\S]+/)。
//captures '1-a_6' but not '543-azser-sder'router.get('/[0-9]+-[[\\w]]*', function);//captures '1-a_6' and '543-az(ser"-sder' but not '5-a s'router.get('/[0-9]+-[[\\S]]*', function);//captures all (equivalent to '.*')router.get('[[\\s\\S]]*', function);
app.path()
通過這個方法可以得到app典型的路徑,其是一個string。
var app = express(), blog = express(), blogAdmin = express();app.use('/blog', blog);app.use('/admin', blogAdmin);console.log(app.path()); // ''console.log(blog.path()); // '/blog'console.log(blogAdmin.path()); // '/blog/admin'
如果app掛載很復雜下,那么這個方法的行為也會很復雜:一種更好用的方式是使用req.baseUrl來獲得這個app的典型路徑。
app.post(path, callback, [callback ...])
路由HTTP POST請求到有特殊回調的特殊路徑。獲取更多的信息,可以查閱routing guide。
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果請求沒能滿足當前路由的處理條件,那么傳遞控制到隨后的路由。
app.post('/', function(req, res) {res.send('POST request to homepage')});
app.put(path, callback, [callback ...])
路由HTTP PUT請求到有特殊回調的特殊路徑。獲取更多的信息,可以查閱routing guide。
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果請求沒能滿足當前路由的處理條件,那么傳遞控制到隨后的路由。
app.put('/', function(req, res) {res.send('PUT request to homepage');});
app.render(view, [locals], callback)
通過callback回調返回一個view渲染之后得到的HTML文本。它可以接受一個可選的參數,可選參數包含了這個view需要用到的本地數據。這個方法類似於res.render(),除了它不能把渲染得到的HTML文本發送給客戶端。
將
app.render()當作是可以生成渲染視圖字符串的工具方法。在res.render()內部,就是使用的app.render()來渲染視圖。如果使能了視圖緩存,那么本地變量緩存就會保留。如果你想在開發的過程中緩存視圖,設置它為
true。在生產環境中,視圖緩存默認是打開的。
app.render('email', function(err, html) {// ...});app.render('email', {name:'Tobi'}, function(err, html) {// ...});
app.route(path)
返回一個單例模式的路由的實例,之后你可以在其上施加各種HTTP動作的中間件。使用app.route()來避免重復路由名字(例如錯字錯誤)--說的意思應該是使用app.router()這個單例方法來避免同一個路徑多個路由實例。
var app = express();app.route('/events').all(function(req, res, next) {// runs for all HTTP verbs first// think of it as route specific middleware!}).get(function(req, res, next) {res.json(...);}).post(function(req, res, next) {// maybe add a new event...})
app.set(name, value)
給name設置項賦value值,name是app settings table中屬性的一項。
對於一個類型是布爾型的屬性調用app.set('foo', ture)等價於調用app.enable('foo')。同樣的,調用app.set('foo', false)等價於調用app.disable('foo')。
可以使用app.get()來取得設置的值:
app.set('title', 'My Site');app.get('title'); // 'My Site'
Application Settings
如果name是程序設置之一,它將影響到程序的行為。下邊列出了程序中的設置。
| 屬性 | 類型 | 值 | 默認 |
|---|---|---|---|
| case sensitive routing | Boolean | 啟用區分大小寫。 | 不啟用。對/Foo和/foo處理是一樣。 |
| env | String | 環境模型。 | process.env.NODE_ENV(NODE_ENV環境變量)或者"development" |
| etag | Varied | 設置ETag響應頭。可取的值,可以查閱etag options table。更多關於HTTP ETag header。 |
weak |
| jsonp callback name | String | 指定默認JSONP回調的名稱。 | ?callback= |
| json replacer | String | JSON替代品回調 | null |
| json spaces | Number | 當設置了這個值后,發送縮進空格美化過的JSON字符串。 | Disabled |
| query parser | Varied | 設置值為false來禁用query parser,或者設置simple,extended,也可以自己實現query string解析函數。simple基於Node原生的query解析,querystring。 |
"extend" |
| strict routing | Boolean | 啟用嚴格的路由。 | 不啟用。對/foo和/foo/的路由處理是一樣。 |
| subdomain offset | Number | 用來刪除訪問子域的主機點分部分的個數 | 2 |
| trust proxy | Varied | 指示app在一個反向代理的后面,使用x-Forwarded-*來確定連接和客戶端的IP地址。注意:X-Forwarded-*頭部很容易被欺騙,所有檢測客戶端的IP地址是靠不住的。trust proxy默認不啟用。當啟用時,Express嘗試通過前端代理或者一系列代理來獲取已連接的客戶端IP地址。req.ips屬性包含了已連接客戶端IP地址的一個數組。為了啟動它,需要設置在下面trust proxy options table中定義的值。trust proxy的設置實現使用了proxy-addr包。如果想獲得更多的信息,可以查閱它的文檔 |
Disable |
| views | String or Array | view所在的目錄或者目錄數組。如果是一個數組,將按在數組中的順序來查找view。 |
process.cwd() + '/views' |
| view cache | Boolean | 啟用視圖模板編譯緩存。 | 在生成環境默認開啟。 |
| view engine | String | 省略時,默認的引擎被擴展使用。 | |
| x-powered-by | Boolean | 啟用X-Powered-By:ExpressHTTP頭部 |
true |
Options for trust proxy settings
查閱Express behind proxies來獲取更多信息。
| Type | Value |
|---|---|
| Boolean | 如果為 |
| IP addresses | 一個IP地址,子網,或者一組IP地址,和委托子網。下面列出的是一個預先配置的子網名列表。
使用下面方法中的任何一種來設置IP地址: 當指定IP地址之后, 這個IP地址或子網會被設置了這個IP地址或子網的`app`排除在外, 最靠近程序服務的沒有委托的地址將被看做客戶端IP地址。 |
| Number | 信任從反向代理到app中間小於等於n跳的連接為客戶端。 |
| Function | 客戶自定義委托代理信任機制。如果你使用這個,請確保你自己知道你在干什么。 |
Options for etag settings ETag功能的實現使用了etag包。如果你需要獲得更多的信息,你可以查閱它的文檔。
| Type | Value |
|---|---|
| Boolean | 設置為 |
| String | 如果是strong,使能strong ETag。如果是weak,啟用weak ETag。 |
| Function | 客戶自定義`ETag`方法的實現. 如果你使用這個,請確保你自己知道你在干什么。 |
app.use([path,], function [, function...])
掛載中間件方法到路徑上。如果路徑未指定,那么默認為"/"。
一個路由將匹配任何路徑如果這個路徑以這個路由設置路徑后緊跟着"/"。比如:
app.use('/appale', ...)將匹配"/apple","/apple/images","/apple/images/news"等。中間件中的
req.originalUrl是req.baseUrl和req.path的組合,如下面的例子所示。
app.use('/admin', function(req, res, next) {// GET 'http://www.example.com/admin/new'console.log(req.originalUrl); // '/admin/new'console.log(req.baseUrl); // '/admin'console.log(req.path);// '/new'});
在一個路徑上掛載一個中間件之后,每當請求的路徑的前綴部分匹配了這個路由路徑,那么這個中間件就會被執行。
由於默認的路徑為/,中間件掛載沒有指定路徑,那么對於每個請求,這個中間件都會被執行。
// this middleware will be executed for every request to the app.app.use(function(req, res, next) {console.log('Time: %d', Date.now());next();});
中間件方法是順序處理的,所以中間件包含的順序是很重要的。
// this middleware will not allow the request to go beyond itapp.use(function(req, res, next) {res.send('Hello World');});// this middleware will never reach this routeapp.use('/', function(req, res) {res.send('Welcome');});
路徑可以是代表路徑的一串字符,一個路徑模式,一個匹配路徑的正則表達式,或者他們的一組集合。
下面是路徑的簡單的例子。
| Type | Example |
|---|---|
| Path | |
| Path Pattern | |
| Regular Expression | |
| Array | |
方法可以是一個中間件方法,一系列中間件方法,一組中間件方法或者他們的集合。由於router和app實現了中間件接口,你可以像使用其他任一中間件方法那樣使用它們。
| Usage | Example |
|---|---|
| 單個中間件 | 你可以局部定義和掛載一個中間件。 一個router是有效的中間件。 一個Express程序是一個有效的中間件。 |
| 一系列中間件 | 對於一個相同的掛載路徑,你可以掛載超過一個的中間件。 |
| 一組中間件 | 在邏輯上使用一個數組來組織一組中間件。如果你傳遞一組中間件作為第一個或者唯一的參數,接着你需要指定掛載的路徑。 |
| 組合 | 你可以組合下面的所有方法來掛載中間件。 |
下面是一些例子,在Express程序中使用express.static中間件。
為程序托管位於程序目錄下的public目錄下的靜態資源:
// GET /style.css etcapp.use(express.static(__dirname + '/public'));
在/static路徑下掛載中間件來提供靜態資源托管服務,只當請求是以/static為前綴的時候。
// GET /static/style.css etc.app.use('/static', express.static(express.__dirname + '/public'));
通過在設置靜態資源中間件之后加載日志中間件來關閉靜態資源請求的日志。
app.use(express.static(__dirname + '/public'));app.use(logger());
托管靜態資源從不同的路徑,但./public路徑比其他更容易被匹配:
app.use(express.static(__dirname + '/public'));app.use(express.static(__dirname + '/files'));app.use(express.static(__dirname + '/uploads'));
Request
req對象代表了一個HTTP請求,其具有一些屬性來保存請求中的一些數據,比如query string,parameters,body,HTTP headers等等。在本文檔中,按照慣例,這個對象總是簡稱為req(http響應簡稱為res),但是它們實際的名字由這個回調方法在那里使用時的參數決定。
如下例子:
app.get('/user/:id', function(req, res) {res.send('user' + req.params.id);});
其實你也可以這樣寫:
app.get('/user/:id', function(request, response) {response.send('user' + request.params.id);});
Properties
在Express 4中,req.files默認在req對象中不再是可用的。為了通過req.files對象來獲得上傳的文件,你可以使用一個multipart-handling(多種處理的工具集)中間件,比如busboy,multer,formidable,multipraty,connect-multiparty或者pez。
req.app
這個屬性持有express程序實例的一個引用,其可以作為中間件使用。
如果你按照這個模式,你創建一個模塊導出一個中間件,這個中間件只在你的主文件中require()它,那么這個中間件可以通過req.app來獲取express的實例。
例如:
// index.jsapp.get("/viewdirectory", require('./mymiddleware.js'));
// mymiddleware.jsmodule.exports = function(req, res) {res.send('The views directory is ' + req.app.get('views'));};
req.baseUrl
一個路由實例掛載的Url路徑。
var greet = express.Router();greet.get('/jp', function(req, res) {console.log(req.baseUrl); // greetres.send('Konichiwa!');});app.use('/greet', greet);
即使你使用的路徑模式或者一系列路徑模式來加載路由,baseUrl屬性返回匹配的字符串,而不是路由模式。下面的例子,greet路由被加載在兩個路徑模式上。
app.use(['/gre+t', 'hel{2}o'], greet); // load the on router on '/gre+t' and '/hel{2}o'
當一個請求路徑是/greet/jp,baseUrl是/greet,當一個請求路徑是/hello/jp,req.baseUrl是/hello。 req.baseUrl和app對象的mountpath屬性相似,除了app.mountpath返回的是路徑匹配模式。
req.body
在請求的body中保存的是提交的一對對鍵值數據。默認情況下,它是undefined,當你使用比如body-parser和multer這類解析body數據的中間件時,它是填充的。
下面的例子,給你展示了怎么使用body-parser中間件來填充req.body。
var app = require('express');var bodyParser = require('body-parser');var multer = require('multer');// v1.0.5var upload = multer(); // for parsing multipart/form-dataapp.use(bodyParser.json()); // for parsing application/jsonapp.use(bodyParser.urlencoded({extended:true})); // for parsing application/x-www-form-urlencodedapp.post('/profile', upload.array(), function(req, res, next) {console.log(req.body);res.json(req.body);});
req.cookies
當使用cookie-parser中間件的時候,這個屬性是一個對象,其包含了請求發送過來的cookies。如果請求沒有帶cookies,那么其值為{}。
// Cookie: name=tjreq.cookies.name// => "tj"
獲取更多信息,問題,或者關注,可以查閱cookie-parser。
req.fresh
指示這個請求是否是新鮮的。其和req.stale是相反的。
當cache-control請求頭沒有no-cache指示和下面中的任一一個條件為true,那么其就為true:
if-modified-since請求頭被指定,和last-modified請求頭等於或者早於modified響應頭。if-none-match請求頭是*。if-none-match請求頭在被解析進它的指令之后,和etag響應頭的值不相等
ps:If-None-Match作用: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 當用戶再次請求該資源時,將在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服務器驗證資源的ETag沒有改變(該資源沒有更新),將返回一個304狀態告訴客戶端使用本地緩存文件。否則將返回200狀態和新的資源和Etag. 使用這樣的機制將提高網站的性能
req.fresh// => true
req.hostname
包含了源自HostHTTP頭部的hostname。
當trust proxy設置項被設置為啟用值,X-Forwarded-Host頭部被使用來代替Host。這個頭部可以被客戶端或者代理設置。
// Host: "example.com"req.hostname// => "example.com"
req.ips
當trust proxy設置項被設置為啟用值,這個屬性包含了一組在X-Forwarded-For請求頭中指定的IP地址。不然,其就包含一個空的數組。這個頭部可以被客戶端或者代理設置。
例如,如果X-Forwarded-For是client,proxy1,proxy2,req.ips就是["clinet", "proxy1", "proxy2"],這里proxy2就是最遠的下游。
req.originalUrl
req.url不是一個原生的Express屬性,它繼承自Node's http module。
這個屬性很像req.url;然而,其保留了原版的請求鏈接,允許你自由地重定向req.url到內部路由。比如,app.use()的mounting特點可以重定向req.url跳轉到掛載點。
// GET /search?q=somethingreq.originalUrl// => "/search?q=something"
req.params
一個對象,其包含了一系列的屬性,這些屬性和在路由中命名的參數名是一一對應的。例如,如果你有/user/:name路由,name屬性可作為req.params.name。這個對象默認值為{}。
// GET /user/tjreq.params.name// => "tj"
當你使用正則表達式來定義路由規則,捕獲組的組合一般使用req.params[n],這里的n是第幾個捕獲租。這個規則被施加在無名通配符匹配,比如/file/*的路由:
// GET /file/javascripts/jquery.jsreq.params[0]// => "javascripts/jquery.js"
req.path
包含請求URL的部分路徑。
// example.com/users?sort=descreq.path// => "/users"
當在一個中間件中被調用,掛載點不包含在
req.path中。你可以查閱app.use()獲得跟多的信息。
req.protocol
請求的協議,一般為http,當啟用TLS加密,則為https。
當trust proxy設置一個啟用的參數,如果存在X-Forwarded-Proto頭部的話,其將被信賴和使用。這個頭部可以被客戶端或者代理設置。
req.ptotocol// => "http"
req.query
一個對象,為每一個路由中的query string參數都分配一個屬性。如果沒有query string,它就是一個空對象,{}。
// GET /search?q=tobi+ferretreq.query.q// => "tobi ferret"// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=conversereq.query.order// => "desc"req.query.shoe.color// => "blue"req.query.shoe.type// => "converse"
req.route
當前匹配的路由,其為一串字符。比如:
app.get('/user/:id?', function userIdHandler(req, res) {console.log(req.route);res.send('GET')})
前面片段的輸出為:
{ path:"/user/:id?"stack:[{ handle:[Function:userIdHandler],name:"userIdHandler",params:undefined,path:undefined,keys:[],regexp:/^\/?$/i,method:'get'}]methods:{get:true}}
req.secure
一個布爾值,如果建立的是TLS的連接,那么就為true。等價與:
'https' == req.protocol;
req.signedCookies
當使用cookie-parser中間件的時候,這個屬性包含的是請求發過來的簽名cookies,這個屬性取得的是不含簽名,可以直接使用的值。簽名的cookies保存在不同的對象中來體現開發者的意圖;不然,一個惡意攻擊可以被施加在req.cookie值上(它是很容易被欺騙的)。記住,簽名一個cookie不是把它藏起來或者加密;而是簡單的防止篡改(因為簽名使用的加密是私人的)。如果沒有發送簽名的cookie,那么這個屬性默認為{}。
// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3req.signedCookies.user// => "tobi"
為了獲取更多的信息,問題或者關注,可以參閱cookie-parser。
req.stale
指示這個請求是否是stale(陳舊的),它與req.fresh是相反的。更多信息,可以查看req.fresh。
req.stale// => true
req.subdomains
請求中域名的子域名數組。
// Host: "tobi.ferrets.example.com"req.subdomains// => ["ferrets", "tobi"]
req.xhr
一個布爾值,如果X-Requested-With的值為XMLHttpRequest,那么其為true,其指示這個請求是被一個客服端庫發送,比如jQuery。
req.xhr// => true
Methods
req.accepts(types)
檢查這個指定的內容類型是否被接受,基於請求的Accept HTTP頭部。這個方法返回最佳匹配,如果沒有一個匹配,那么其返回undefined(在這個case下,服務器端應該返回406和"Not Acceptable")。 type值可以是一個單的MIME type字符串(比如application/json),一個擴展名比如json,一個逗號分隔的列表,或者一個數組。對於一個列表或者數組,這個方法返回最佳項(如果有的話)。
// Accept: text/htmlreq.accepts('html');// => "html"// Accept: text/*, application/jsonreq.accepts('html');// => "html"req.accepts('text/html');// => "text/html"req.accepts(['json', 'text']);// => "json"req.accepts('application/json');// => "application/json"// Accept: text/*, application/jsonreq.accepts('image/png');req.accepts('png');// => undefined// Accept: text/*;q=.5, application/jsonreq.accepts(['html', 'json']);// => "json"
獲取更多信息,或者如果你有問題或關注,可以參閱accepts。
req.acceptsCharsets(charset[, ...])
返回指定的字符集集合中第一個的配置的字符集,基於請求的Accept-CharsetHTTP頭。如果指定的字符集沒有匹配的,那么就返回false。
獲取更多信息,或者如果你有問題或關注,可以參閱accepts。
req.acceptsEncodings(encoding[, ...])
返回指定的編碼集合中第一個的配置的編碼,基於請求的Accept-EncodingHTTP頭。如果指定的編碼集沒有匹配的,那么就返回false。
獲取更多信息,或者如果你有問題或關注,可以參閱accepts。
req.acceptsLanguages(lang [, ...])
返回指定的語言集合中第一個的配置的語言,基於請求的Accept-LanguageHTTP頭。如果指定的語言集沒有匹配的,那么就返回false。
獲取更多信息,或者如果你有問題或關注,可以參閱accepts。
req.get(field)
返回指定的請求HTTP頭部的域內容(不區分大小寫)。Referrer和Referer的域內容可互換。
req.get('Content-type');// => "text/plain"req.get('content-type');// => "text/plain"req.get('Something')// => undefined
其是req.header(field)的別名。
req.is(type)
如果進來的請求的Content-type頭部域匹配參數type給定的MIME type,那么其返回true。否則返回false。
// With Content-Type: text/html; charset=utf-8req.is('html');req.is('text/html');req.is('text/*');// => true// When Content-Type is application/jsonreq.is('json');req.is('application/json');req.is('application/*');// => truereq.is('html');// => false
獲取更多信息,或者如果你有問題或關注,可以參閱type-is。
req.param(naem, [, defaultValue])
過時的。可以在適合的情況下,使用
req.params,req.body或者req.query。
返回當前參數name的值。
// ?name=tobireq.param('name')// => "tobi"// POST name=tobireq.param('name')// => "tobi"// /user/tobi for /user/:namereq.param('name')// => "tobi"
按下面給出的順序查找:
- req.params
- req.body
- req.query
可選的,你可以指定一個defaultValue來設置一個默認值,如果這個參數在任何一個請求的對象中都不能找到。
直接通過
req.params,req.body,req.query取得應該更加的清晰-除非你確定每一個對象的輸入。Body-parser中間件必須加載,如果你使用req.param()。詳細請看req.body。
Response
res對象代表了當一個HTTP請求到來時,Express程序返回的HTTP響應。在本文檔中,按照慣例,這個對象總是簡稱為res(http請求簡稱為req),但是它們實際的名字由這個回調方法在那里使用時的參數決定。
例如:
app.get('/user/:id', function(req, res) {res.send('user' + req.params.id);});
這樣寫也是一樣的:
app.get('/user/:id', function(request, response) {response.send('user' + request.params.id);});
Properties
res.app
這個屬性持有express程序實例的一個引用,其可以在中間件中使用。 res.app和請求對象中的req.app屬性是相同的。
res.headersSent
布爾類型的屬性,指示這個響應是否已經發送HTTP頭部。
app.get('/', function(req, res) {console.log(res.headersSent); // falseres.send('OK'); // send之后就發送了頭部console.log(res.headersSent); // true});
res.locals
一個對象,其包含了本次請求的響應中的變量和因此它的變量只提供給本次請求響應的周期內視圖渲染里使用(如果有視圖的話)。
其他方面,其和app.locals是一樣的。
這個參數在導出請求級別的信息是很有效的,這些信息比如請求路徑,已認證的用戶,用戶設置等等。
app.use(function(req, res, next) {res.locals.user = req.user;res.locals.authenticated = !req.user.anonymous;next();});
Methods
res.append(field [, value])
res.append()方法在
Expresxs4.11.0以上版本才支持。
在指定的field的HTTP頭部追加特殊的值value。如果這個頭部沒有被設置,那么將用value新建這個頭部。value可以是一個字符串或者數組。
注意:在res.append()之后調用app.set()函數將重置前面設置的值。
res.append('Lind', ['<http://localhost>', '<http://localhost:3000>']);res.append('Set-Cookie', 'foo=bar;Path=/;HttpOnly');res.append('Warning', '199 Miscellaneous warning');
res.attachment([filename])
設置HTTP響應的Content-Disposition頭內容為"attachment"。如果提供了filename,那么將通過res.type()獲得擴展名來設置Content-Type,並且設置Content-Disposition內容為"filename="parameter。
res.attachment();// Content-Disposition: attachmentres.attachment('path/to/logo.png');// Content-Disposition: attachment; filename="logo.png"// Content-Type: image/png
res.cookie(name, value [,options])
設置name和value的cookie,value參數可以是一串字符或者是轉化為json字符串的對象。
options是一個對象,其可以有下列的屬性。
| 屬性 | 類型 | 描述 |
|---|---|---|
| domain | String | 設置cookie的域名。默認是你本app的域名。 |
| expires | Date | cookie的過期時間,GMT格式。如果沒有指定或者設置為0,則產生新的cookie。 |
| httpOnly | Boolean | 這個cookie只能被web服務器獲取的標示。 |
| maxAge | String | 是設置過去時間的方便選項,其為過期時間到當前時間的毫秒值。 |
| path | String | cookie的路徑。默認值是/。 |
| secure | Boolean | 標示這個cookie只用被HTTPS協議使用。 |
| signed | Boolean | 指示這個cookie應該是簽名的。 |
res.cookie()所作的都是基於提供的
options參數來設置Set-Cookie頭部。沒有指定任何的options,那么默認值在RFC6265中指定。
使用實例:
res.cookie('name', 'tobi', {'domain':'.example.com', 'path':'/admin', 'secure':true});res.cookie('remenberme', '1', {'expires':new Date(Date.now() + 90000), 'httpOnly':true});
maxAge是一個方便設置過期時間的方便的選項,其以當前時間開始的毫秒數來計算。下面的示例和上面的第二條功效一樣。
res.cookie('rememberme', '1', {'maxAge':90000}, "httpOnly":true);
你可以設置傳遞一個對象作為value的參數。然后其將被序列化為Json字符串,被bodyParser()中間件解析。
res.cookie('cart', {'items':[1, 2, 3]});res.cookie('cart', {'items':[1, 2, 3]}, {'maxAge':90000});
當我們使用cookie-parser中間件的時候,這個方法也支持簽名的cookie。簡單地,在設置options時包含signed選項為true。然后res.cookie()將使用傳遞給cookieParser(secret)的密鑰來簽名這個值。
res.cookie('name', 'tobi', {'signed':true});
res.clearCookie(name [,options])
根據指定的name清除對應的cookie。更多關於options對象可以查閱res.cookie()。
res.cookie('name', 'tobi', {'path':'/admin'});res.clearCookie('name', {'path':'admin'});
res.download(path, [,filename], [,fn])
傳輸path指定文件作為一個附件。通常,瀏覽器提示用戶下載。默認情況下,Content-Disposition頭部"filename="的參數為path(通常會出現在瀏覽器的對話框中)。通過指定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) {// Handle error, but keep in mind the response may be partially-sent// so check res.headersSentif (err) {} else {// decrement a download credit, etc.}});
res.end([data] [, encoding])
結束本響應的過程。這個方法實際上來自Node核心模塊,具體的是response.end() method of http.ServerResponse。
用來快速結束請求,沒有任何的數據。如果你需要發送數據,可以使用res.send()和res.json()這類的方法。
res.end();res.status(404).end();
res.format(object)
進行內容協商,根據請求的對象中AcceptHTTP頭部指定的接受內容。它使用req.accepts()來選擇一個句柄來為請求服務,這些句柄按質量值進行排序。如果這個頭部沒有指定,那么第一個方法默認被調用。當不匹配時,服務器將返回406"Not Acceptable",或者調用default回調。 Content-Type請求頭被設置,當一個回調方法被選擇。然而你可以改變他,在這個方法中使用這些方法,比如res.set()或者res.type()。
下面的例子,將回復{"message":"hey"},當請求的對象中Accept頭部設置成"application/json"或者"*/json"(不過如果是*/*,然后這個回復就是"hey")。
res.format({'text/plain':function() {res.send('hey');},'text/html':function() {res.send('<p>hey</p>');},'application/json':function() {res.send({message:'hey'});},'default':function() {res.status(406).send('Not Acceptable');}})
除了規范化的MIME類型之外,你也可以使用拓展名來映射這些類型來避免冗長的實現:
res.format({text:function() {res.send('hey');},html:function() {res.send('<p>hey</p>');},json:function() {res.send({message:'hey'});}})
res.get(field)
返回field指定的HTTP響應的頭部。匹配是區分大小寫。
res.get('Content-Type');// => "text/plain"
res.json([body])
發送一個json的響應。這個方法和將一個對象或者一個數組作為參數傳遞給res.send()方法的效果相同。不過,你可以使用這個方法來轉換其他的值到json,例如null,undefined。(雖然這些都是技術上無效的JSON)。
res.json(null);res.json({user:'tobi'});res.status(500).json({error:'message'});
res.jsonp([body])
發送一個json的響應,並且支持JSONP。這個方法和res.json()效果相同,除了其在選項中支持JSONP回調。
res.jsonp(null)// => nullres.jsonp({user:'tobi'})// => {"user" : "tobi"}res.status(500).jsonp({error:'message'})// => {"error" : "message"}
默認情況下,jsonp的回調方法簡單寫作callback。可以通過jsonp callback name設置來重寫它。
下面是一些例子使用JSONP響應,使用相同的代碼:
// ?callback=foores.jsonp({user:'tobo'})// => foo({"user":"tobi"})app.set('jsonp callback name', 'cb')// ?cb=foores.status(500).jsonp({error:'message'})// => foo({"error":"message"})
res.links(links)
連接這些links,links是以傳入參數的屬性形式提供,連接之后的內容用來填充響應的Link HTTP頭部。
res.links({next:'http://api.example.com/users?page=2',last:'http://api.example.com/user?page=5'});
效果:
Link:<http://api.example.com/users?page=2>;rel="next",<http://api.example.com/users?page=5>;rel="last"
res.location(path)
設置響應的LocationHTTP頭部為指定的path參數。
res.location('/foo/bar');res.location('http://example.com');res.location('back');
當path參數為back時,其具有特殊的意義,其指定URL為請求對象的Referer頭部指定的URL。如果請求中沒有指定,那么其即為"/"。
Express傳遞指定的URL字符串作為回復給瀏覽器響應中的
Location頭部的值,不檢測和操作,除了back這個參數。瀏覽器會將用戶重定向到location設置的url或者Referer的url(back參數的情況)
res.redirect([status,] path)
重定向來源於指定path的URL,以及指定的HTTP status codestatus。如果你沒有指定status,status code默認為"302 Found"。
res.redirect('/foo/bar');res.redirect('http://example.com');res.redirect(301, 'http://example.com');res.redirect('../login');
重定向也可以是完整的URL,來重定向到不同的站點。
res.redirect('http://google.com');
重定向也可以相對於主機的根路徑。比如,如果程序的路徑為http://example.com/admin/post/new,那么下面將重定向到http://example.com/admim:
res.redirect('/admin');
重定向也可以相對於當前的URL。比如,來之於http://example.com/blog/admin/(注意結尾的/),下面將重定向到http://example.com/blog/admin/post/new。
res.redirect('post/new');
如果來至於http://example.com/blog/admin(沒有尾部/),重定向post/new,將重定向到http://example.com/blog/post/new。如果你覺得上面很混亂,可以把路徑段認為目錄(有'/')或者文件,這樣是可以的。相對路徑的重定向也是可以的。如果你當前的路徑為http://example.com/admin/post/new,下面的操作將重定向到http://example.com/admin/post:
res.redirect('..');
back將重定向請求到referer,當沒有referer的時候,默認為/。
res.redirect('back');
res.render(view [, locals] [, callback])
渲染一個視圖,然后將渲染得到的HTML文檔發送給客戶端。可選的參數為:
locals,定義了視圖本地參數屬性的一個對象。callback,一個回調方法。如果提供了這個參數,render方法將返回錯誤和渲染之后的模板,並且不自動發送響應。當有錯誤發生時,可以在這個回調內部,調用next(err)方法。
本地變量緩存使能視圖緩存。在開發環境中緩存視圖,需要手動設置為true;視圖緩存在生產環境中默認開啟。
// send the rendered view to the clientres.render('index');// if a callback is specified, the render HTML string has to be sent explicitlyres.render('index', function(err, html) {res.send(html);});// pass a local variable to the viewres.render('user', {name:'Tobi'}, function(err, html) {// ...});
res.send([body])
發送HTTP響應。 body參數可以是一個Buffer對象,一個字符串,一個對象,或者一個數組。比如:
res.send(new Buffer('whoop'));res.send({some:'json'});res.send('<p>some html</p>');res.status(404).send('Sorry, we cannot find that!');res.status(500).send({ error: 'something blew up' });
對於一般的非流請求,這個方法可以執行許多有用的的任務:比如,它自動給Content-LengthHTTP響應頭賦值(除非先前定義),也支持自動的HEAD和HTTP緩存更新。
當參數是一個Buffer對象,這個方法設置Content-Type響應頭為application/octet-stream,除非事先提供,如下所示:
res.set('Content-Type', 'text/html');res.send(new Buffer('<p>some html</p>'));
當參數是一個字符串,這個方法設置Content-Type響應頭為text/html:
res.send('<p>some html</p>');
當參數是一個對象或者數組,Express使用JSON格式來表示:
res.send({user:'tobi'});res.send([1, 2, 3]);
res.sendFile(path [, options] [, fn])
res.sendFile()從Express v4.8.0開始支持。
傳輸path指定的文件。根據文件的擴展名設置Content-TypeHTTP頭部。除非在options中有關於root的設置,path一定是關於文件的絕對路徑。
下面的表提供了options參數的細節:
| 屬性 | 描述 | 默認值 | 可用版本 |
|---|---|---|---|
| maxAge | 設置Cache-Control的max-age屬性,格式為毫秒數,或者是ms format的一串字符串 |
0 | |
| root | 相對文件名的根目錄 | ||
| lastModified | 設置Last-Modified頭部為此文件在系統中的最后一次修改時間。設置false來禁用它 |
Enable | 4.9.0+ |
| headers | 一個對象,包含了文件相關的HTTP頭部。 | ||
| dotfiles | 是否支持點開頭文件名的選項。可選的值"allow","deny","ignore" | "ignore" |
當傳輸完成或者發生了什么錯誤,這個方法調用fn回調方法。如果這個回調參數指定了和一個錯誤發生,回調方法必須明確地通過結束請求-響應循環或者傳遞控制到下個路由來處理響應過程。
下面是使用了所有參數的使用res.sendFile()的例子:
app.get('/file/:name', function(req, res, next) {var options = {root:__dirname + '/public',dotfile:'deny',headers:{'x-timestamp':Date.now(),'x-sent':true}};var fileName = req.params.name;res.sendFile(fileName, options, function(err) {if (err) {console.log(err);res.status(err.status).end();}else {console.log('sent', fileName);}});});
res.sendFile提供了文件服務的細粒度支持,如下例子說明:
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('/upload/' + uid + '/' + file);}else {res.status(403).send('Sorry! you cant see that.');}});})
獲取更多信息,或者你有問題或者關注,可以查閱send。
res.sendStatus(statusCode)
設置響應對象的HTTP status code為statusCode並且發送statusCode的相應的字符串形式作為響應的Body。
res.sendStatus(200); // equivalent to res.status(200).send('OK');res.sendStatus(403); // equivalent to res.status(403).send('Forbidden');res.sendStatus(404); // equivalent to res.status(404).send('Not Found');res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')
如果一個不支持的狀態被指定,這個HTTP status依然被設置為statusCode並且用這個code的字符串作為Body。
res.sendStatus(2000); // equivalent to res.status(2000).send('2000');
res.set(field [, value])
設置響應對象的HTTP頭部field為value。為了一次設置多個值,那么可以傳遞一個對象為參數。
res.set('Content-Type', 'text/plain');res.set({'Content-Type':'text/plain','Content-Length':'123','ETag':'123456'})
其和res.header(field [,value])效果一致。
res.status(code)
使用這個方法來設置響應對象的HTTP status。其是Node中response.statusCode的一個連貫性的別名。
res.status(403).end();res.status(400).send('Bad Request');res.status(404).sendFile('/absolute/path/to/404.png');
res.type(type)
程序將設置Content-TypeHTTP頭部的MIME type,如果這個設置的type能夠被mime.lookup解析成正確的Content-Type。如果type中包含了/字符,那么程序會直接設置Content-Type為type。
res.type('.html'); // => 'text/html'res.type('html'); // => 'text/html'res.type('json'); // => 'application/json'res.type('application/json'); // => 'application/json'res.type('png'); // => image/png:
res.vary(field)
在沒有Vary應答頭部時增加Vary應答頭部。
ps:vary的意義在於告訴代理服務器/緩存/CDN,如何判斷請求是否一樣,vary中的組合就是服務器/緩存/CDN判斷的依據,比如Vary中有User-Agent,那么即使相同的請求,如果用戶使用IE打開了一個頁面,再用Firefox打開這個頁面的時候,CDN/代理會認為是不同的頁面,如果Vary中沒有User-Agent,那么CDN/代理會認為是相同的頁面,直接給用戶返回緩存的頁面,而不會再去web服務器請求相應的頁面。通俗的說就相當於
field作為了一個緩存的key來判斷是否命中緩存
res.vary('User-Agent').render('docs');
Router
一個router對象是一個單獨的實例關於中間件和路由。你可以認為其是一個"mini-application"(迷你程序),其具有操作中間件和路由方法的能力。每個Express程序有一個內建的app路由。
路由自身表現為一個中間件,所以你可以使用它作為app.use()方法的一個參數或者作為另一個路由的use()的參數。
頂層的express對象有一個Router()方法,你可以使用Router()來創建一個新的router對象。
Router([options])
如下,可以創建一個路由:
var router = express.Router([options]);
options參數可以指定路由的行為,其有下列選擇:
| 屬性 | 描述 | 默認值 | 可用性 |
|---|---|---|---|
| caseSensitive | 是否區分大小寫 | 默認不啟用。對待/Foo和/foo一樣。 |
|
| mergeParams | 保存父路由的res.params。如果父路由參數和子路由參數沖突,子路由參數優先。 |
false | 4.5.0+ |
| strict | 使能嚴格路由。 | 默認不啟用,/foo和/foo/被路由一樣對待處理 |
你可以將router當作一個程序,可以在其上添加中間件和HTTP路由方法(例如get,put,post等等)。
// invoked for any requests passed to this routerrouter.use(function(req, res, next) {// .. some logic here .. like any other middlewarenext();});// will handle any request that ends in /events// depends on where the router is "use()'d"router.get('/events', function(req, res, next) {// ..});
你可以在一個特別的根URL上掛載一個路由,這樣你就以將你的各個路由放到不同的文件中或者甚至是mini的程序。
// only requests to /calendar/* will be sent to our "router"app.use('/calendar', router);
Methods
router.all(path, [callback, ...] callback)
這個方法和router.METHOD()方法一樣,除了這個方法會匹配所有的HTTP動作。
這個方法對想映射全局的邏輯處理到特殊的路徑前綴或者任意匹配是十分有用的。比如,如果你放置下面所示的這個路由在其他路由的前面,那么其將要求從這個點開始的所有的路由進行驗證操作和自動加載用戶信息。記住,這些全局的邏輯操作,不需要結束請求響應周期:loaduser可以執行一個任務,然后調用next()來將執行流程移交到隨后的路由。
router.all('*', requireAuthentication, loadUser);
相等的形式:
router.all('*', requireAuthentication)router.all('*', loadUser);
這是一個白名單全局功能的例子。這個例子很像前面的,不過其僅僅作用於以/api開頭的路徑:
router.all('/api/*', requireAuthentication);
router.METHOD(path, [callback, ...] callback)
router.METHOD()方法提供了路由方法在Express中,這里的METHOD是HTTP方法中的一個,比如GET,PUT,POST等等,但router中的METHOD是小寫的。所以,實際的方法是router.get(),router.put(),router.post()等等。
你可以提供多個回調函數,它們的行為和中間件一樣,除了這些回調可以通過調用next('router')來繞過剩余的路由回調。你可以使用這個機制來為一個路由設置一些前提條件,如果請求沒有滿足當前路由的處理條件,那么傳遞控制到隨后的路由。
下面的片段可能說明了最簡單的路由定義。Experss轉換path字符串為正則表達式,用於內部匹配傳入的請求。在匹配的時候,是不考慮Query strings,例如,"GET /"將匹配下面的路由,"GET /?name=tobi"也是一樣的。
router.get('/', function(req, res) {res.send('Hello World');});
如果你對匹配的path有特殊的限制,你可以使用正則表達式,例如,下面的可以匹配"GET /commits/71dbb9c"和"GET /commits/71bb92..4c084f9"。
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res) {var from = req.params[0];var to = req.params[1];res.send('commit range ' + from + '..' + to);});
router.param(name, callback)
給路由參數添加回調觸發器,這里的name是參數名,function是回調方法。回調方法的參數按序是請求對象,響應對象,下個中間件,參數值和參數名。雖然name在技術上是可選的,但是自Express V4.11.0之后版本不推薦使用(見下面)。
不像
app.param(),router.param()不接受一個數組作為路由參數。
例如,當:user出現在路由路徑中,你可以映射用戶加載的邏輯處理來自動提供req.user給這個路由,或者對輸入的參數進行驗證。
router.param('user', function(req, res, next, id) {User.find(id, function(error, user) {if (err) {next(err);}else if (user){req.user = user;} else {next(new Error('failed to load user'));}});});
對於Param的回調定義的路由來說,他們是局部的。它們不會被掛載的app或者路由繼承。所以,定義在router上的param回調只有是在router上的路由具有這個路由參數時才起作用。
在定義param的路由上,param回調都是第一個被調用的,它們在一個請求-響應循環中都會被調用一次並且只有一次,即使多個路由都匹配,如下面的例子:
router.param('id', function(req, res, next, id) {console.log('CALLED ONLY ONCE');next();});router.get('/user/:id', function(req, res, next) {console.log('although this matches');next();});router.get('/user/:id', function(req, res) {console.log('and this mathces too');res.end();});
當GET /user/42,得到下面的結果:
CALLED ONLY ONCEalthough this matchesand this matches too
`
下面章節描述的
router.param(callback)在v4.11.0之后被棄用。
通過只傳遞一個回調參數給router.param(name, callback)方法,router.param(naem, callback)方法的行為將被完全改變。這個回調參數是關於router.param(name, callback)該具有怎樣的行為的一個自定義方法,這個方法必須接受兩個參數並且返回一個中間件。
這個回調的第一個參數就是需要捕獲的url的參數名,第二個參數可以是任一的JavaScript對象,其可能在實現返回一個中間件時被使用。
這個回調方法返回的中間件決定了當URL中包含這個參數時所采取的行為。
在下面的例子中,router.param(name, callback)參數簽名被修改成了router.param(name, accessId)。替換接受一個參數名和回調,router.param()現在接受一個參數名和一個數字。
var express = require('express');var app = express();var router = express.Router();router.param(function(param, option){return function(req, res, next, val) {if (val == option) {next();}else {res.sendStatus(403);}}});router.param('id', 1337);router.get('/user/:id', function(req, res) {res.send('Ok');});app.use(router);app.listen(3000, function() {console.log('Ready');});
在這個例子中,router.param(name. callback)參數簽名保持和原來一樣,但是替換成了一個中間件,定義了一個自定義的數據類型檢測方法來檢測user id的類型正確性。
router.param(function(param, validator) {return function(req, res, next, val) {if (validator(val)) {next();}else {res.sendStatus(403);}}});router.param('id', function(candidate) {return !isNaN(parseFloat(candidate)) && isFinite(candidate);});
router.route(path)
返回一個單例模式的路由的實例,之后你可以在其上施加各種HTTP動作的中間件。使用router.route()來避免重復路由名字(例如錯字錯誤)--說的意思應該是使用router.route()這個單例方法來避免同一個路徑多個路由實例。
構建在上面的router.param()例子之上,下面的代碼展示了怎么使用router.route()來指定各種HTTP方法的處理句柄。
var router = express.Router();router.param('user_id', function(req, res, next, id) {// sample user, would actually fetch from DB, etc...req.user = {id:id,name:"TJ"};next();});router.route('/users/:user_id').all(function(req, res, next) {// runs for all HTTP verbs first// think of it as route specific middleware!next();}).get(function(req, res, next) {res.json(req.user);}).put(function(req, res, next) {// just an example of maybe updating the userreq.user.name = req.params.name;// save user ... etcres.json(req.user);}).post(function(req, res, next) {next(new Error('not implemented'));}).delete(function(req, res, next) {next(new Error('not implemented'));})
這種方法重復使用單個/usrs/:user_id路徑來添加了各種的HTTP方法。
router.use([path], [function, ...] function)
給可選的path參數指定的路徑掛載給定的中間件方法,未指定path參數,默認值為/。
這個方法類似於app.use()。一個簡單的例子和用例在下面描述。查閱app.use()獲得更多的信息。
中間件就像一個水暖管道,請求在你定義的第一個中間件處開始,順着中間件堆棧一路往下,如果路徑匹配則處理這個請求。
var express = require('express');var app = express();var router = express.Router();// simple logger for this router`s requests// all requests to this router will first hit this middlewarerouter.use(function(req, res, next) {console.log('%s %s %s', req.method, req.url, req.path);next();})// this will only be invoked if the path starts with /bar form the mount ponitrouter.use('/bar', function(req, res, next) {// ... maybe some additional /bar logging ...next();})// always be invokedrouter.use(function(req, res, next) {res.send('hello world');})app.use('/foo', router);app.listen(3000);
對於中間件function,掛載的路徑是被剝離的和不可見的。關於這個特性主要的影響是對於不同的路徑,掛載相同的中間件可能對代碼不做改動,盡管其前綴已經改變。
你使用router.use()定義中間件的順序很重要。中間們是按序被調用的,所以順序決定了中間件的優先級。例如,通常日志是你將使用的第一個中間件,以便每一個請求都被記錄。
var logger = require('morgan');router.use(logger());router.use(express.static(__dirname + '/public'));router.use(function(req, res) {res.send('Hello');});
現在為了支持你不希望記錄靜態文件請求,但為了繼續記錄那些定義在logger()之后的路由和中間件。你可以簡單的將static()移動到前面來解決:
router.use(express.static(__dirname + '/public'));router.use(logger());router.use(function(req, res){res.send('Hello');});
另外一個確鑿的例子是從不同的路徑托管靜態文件,你可以將./public放到前面來獲得更高的優先級:
app.use(express.static(__dirname + '/public'));app.use(express.static(__dirname + '/files'));app.use(express.static(__dirname + '/uploads'));
router.use()方法也支持命名參數,以便你的掛載點對於其他的路由而言,可以使用命名參數來進行預加載,這樣做是很有益的。
