本文檔基於express4.x版本css
mkdir hello && cd hello && npm install express
新建app.js
內容以下node
var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('hello world'); }); app.listen(3000);
node app.js
,而後瀏覽器訪問http://localhost:8888
能夠看到hello world可使用express工具生成應用程序框架,jquery
npm install express-generator -g
express -h
顯示選項express myapp
在當前目錄建立名爲myapp
的express程序cd myapp && npm install
安裝所需模塊set DEBUG=myapp & node ./bin/www
運行apphttp://localhost:3000
路由指肯定程序如何針對特定請求進行反應,這個請求是一個URI和它的HTTP請求方法。git
每個路由有一個處理函數,當路由匹配的時候執行。github
路由定義格式爲:app.VERB(PATH, HANDLER)
,其中app
是一個express實例,VERB
是一個HTTP請求方法,PATH
是服務器上的一個路徑,HANDLER
是用於處理請求的函數。web
一下代碼展現app的基本路由正則表達式
// respond with "Hello World" on the homepage app.get('/', function (req, res) { res.send('Hello World'); }); // accept POST request on the homepage app.post('/', function (req, res) { res.send('Got a POST request'); }); // accept PUT request at /user app.put('/user', function (req, res) { res.send('got a PUT request at /user'); }); // accept DELETE request at /user app.delete('/user', function (req, res) { res.send('got a DELETE request at /user'); });
express程序實質上是一系列的中間件調用。數據庫
中間件是一個能夠訪問請求、相應對象和下一個中間件的函數,中間件功能有:express
若是當前中間件不結束請求-響應週期,它必須調用next()
將控制傳遞給下一個中間件,不然請求將會懸掛。
中間件有一個可選的mount路徑,中間件能夠再應用程序級別或者路由級別進行加載。一樣,一系列的中間件函數能夠同時加載,這就在mount點建立了一箇中間件子棧。
express應用程序可使用一下類型的中間件:
應用程序級別中間件綁定在express示例上,使用app.use()
或者app.VERB()
var app = express(); // a middleware with no mount path; // gets executed for every request to the app app.use(function (req, res, next) { console.log('Time: ', Date.now()); next(); }); // a middleware mounted on /user/:id; // will be executed for any type of HTTP request to /user/:id app.use('/user/:id', function (req, res, next) { console.log('Request Type: ', req.method); next(); }); // a route and its handler function (middleware system) // which handles GET requests to /user/:id app.get('/user/:id', function (req, res, next) { res.send('user'); });
下面代碼在mount點加載一系列中間件
// a middleware sub-stack which prints request info // for any type of HTTP request to /user/:id app.use('/user/:id', function (req, res, next) { console.log('request url: ', req.originUrl); next(); }, function (req, res, next) { console.log('request type: ', req.method); next(); });
路由處理程序,做爲中間件系統的一部分,使得爲同一個路徑定義多個路由成爲可能。下面的例子中,爲GET /user/:id
定義了兩個路由。第二個路由沒有任何語法問題,可是永遠得不到調用,由於第一個路由終止了請求-響應循環。
// a middleware sub-stack which handles GET requests to /user/:id app.get('/user/:id', function (req, res, next) { console.log('id: ', req.params.id); next(); }, function (req, res, next) { res.send('user info'); }); // handler for /user/:id which prints the user id app.get('/user/:id', function (req, res, next) { res.end(req.params.id); });
若是想要跳過路由中間件棧剩下的中間件,調用next('route')
會將控制權轉交給下一個路由。須要注意的是:next('route')
值能在使用app.VERB()
或者router.VERB()
加載的中間件中使用。
// a middleware sub-stack which handles // GET requests to /user/:id app.get('/user/:id', function (req, res, next) { // if user id is 0, skip to the next route if (req.params.id === 0) { next('route'); } // else pass the control to the next middleware in this stack else { next(); } }, function (req, res, next) { res.render('regular'); }); // handler for /user/:id which renders a special page app.get('/user/:id', function (req, res, next) { res.render('special'); });
路由級別中間件與應用程序級別中間件工做同樣,惟一的區別是他們bound toexpress.Router()
的實例
var router = express.Router();
路由級別中間件經過router.use()
或者router.VERB()
加載。
前面應用程序級別的中間件可使用路由級別代替:
var app = express(); var router = express.Router(); // a middleware with no mount path, // get executed for every request to the router router.use(function (req, res, next) { console.log('Time:', Date.now()); next(); }); // a middleware sub-stack shows request // info for any type of HTTP request to /user/:id router.use('/user/:id', function (req, res, next) { console.log('request url:', req.originalUrl); next(); }, function (req, res, next) { console.log('request type:', req.methos); next(); }); // a middle ware sub-stack which handles GET requests to /user/:id router.get('/user/:id', function (req, res, next) { // if user id is 0, skip to the next router if (req.params.id === 0) { next('route'); } // else pass the control to the next middleware in this stack else { next(); } }, function (req, res, next) { res.render('regular'); }); // handler for /user/:id which renders a special page router.get('/user/:id', function (req, res, next) { console.log(req.params.id); res.render('special'); }); // mount the router on the app app.use('/', router);
express4.X以後再也不依賴於Connect。除了自帶express.static
以外,全部其餘中間件都放到單獨模塊中。查看中間件列表
express.static
基於serve-static模塊,負責爲express應用程序提供靜態資源服務。
root
參數爲靜態資源存放的根目錄。
可選的options
對象能夠有如下屬性:
dotfiles
控制點文件服務,可選值爲allow
,deny
,'ignore'默認爲ignore
etag
控制etag生成,默認爲true
extensions
設置文件後綴名補充,默認爲false
index
設置目錄訪問的返回,默認爲index.html
,設置爲false
能夠禁止目錄訪問lastModified
根據文件修改時間設置Last-Modified
報頭,默認true
maxAge
設置Cache-Control報頭的緩存控制時間,單位爲毫秒,默認爲0redirect
當路徑名是目錄時,重定向到包含結尾/
的目錄,默認true
setHeaders
函數用於爲文件設置HTTP頭如下是例子:
var options = { dotfiles: 'ignore', etag: false, extensions: ['htm', 'html'], index: false, maxAge: '1d', redirect: false, setHeaders: function (req, res, stat) { res.set('x-timestamp', Date.now()); } }; app.use(express.static('public', options));
一個應用程序能夠有多個靜態目錄:
app.use(express.static('public')); app.use(express.static('uploads')); app.use(express.static('files'));
訪問serve-static查看詳細選項
express是一個路由和中間件web框架,自身包含不多功能,能夠經過第三方中間件添加所需功能。
安裝所需模塊而且在應用程序級別或者路由級別加載。
下面的例子使用cookie-parser
來解析cookie
npm install cookie-parser
var express = require('express'); var app = express(); var cookieParser = require('cookie-parser'); app.use(cookieParser());
異常處理中間件與其餘中間件相比的區別是函數參數爲四個(err, req, res, next)
app.use(function (err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); });
儘管不是強制的,一般來講錯誤處理中間件定義在最後:
var bodyParser = require('body-parser'); var methodOverride = require('method-override'); app.use(bodyParser()); app.use(methodOverride()); app.use(function (err, req, res, next) { // logic });
錯誤處理中間件返回的內容可使任意的,好比HTML錯誤頁面,簡單的消息,JSON等等。
爲了方便組織,可能須要定義多個錯誤處理中間件,好比你可能想爲XHR請求定義錯誤處理程序。
var bodyParser = require('body-parser'); var methodOverride = require('method-override'); app.use(bodyParser()); app.use(methodOverride()); app.use(logErros); app.use(clientErrorHandler); app.use(errorHandler);
其中logErrors將請求和錯誤信息輸出到stderr
function logErrors(err, req, res, next) { console.error(err.stack); next(err); }
clientErrorHandler定義以下:
function clientErrorHandler(err, req, res, next) { if (req.xhr) { res.status(500) .send({ error: 'Something blew up' }); } else { next(err); } }
最後的errorHandler捕獲全部錯誤
function errorHandler(err, req, res, next) { res.status(500); res.render('error', { error: err }); }
express使用debug模塊來log路由匹配,中間件使用,應用粗模式等。
debug
相似於console.log
可是不一樣的是發佈版本時不須要註釋debug日誌語句,經過環境變量DEBUG
調節日誌輸出
查看express內部日誌的方法:啓動app時設置DEBUG
環境變量爲express:*
DEBUG=express:* node index.js
若是隻想輸出路由信息,設置DEBUG=express:router
,若是隻想查看應用程序相關log,設置DEBUG=express:application
更多debug信息,查看debug guide
在express渲染模板文件以前,必須執行如下設置
app.set('views', './views')
app.set('view engine', 'jade')
而後安裝對應模板引擎的package
npm install jade --save
兼容於express的模板引擎會暴露一個__express(filePath, options, callback)
的接口,用於提供給res.render()
調用來渲染模板
一些模板引擎不遵照這個約定consolidate.js能夠爲流行的node模板引擎建立轉換,這樣就能夠與express無縫銜接。
模板引擎設置好以後,沒必要顯式指定模板引擎或者加載模塊,express會自動加載
app.engine('jade', require('jade').__express);
在視圖目錄下建立一個jade模板文件index.jade
html head title!= title body h1!= message
而後建立一個路由渲染index.jade
app.get('/', function (req, res) { res.render('index', { title: 'hey', message: 'Hello there!' }); });
此時訪問主頁便可看到歡迎界面,查看如何開發express模板引擎能夠學習更多知識
建立express應用程序
var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('hello world'); }); app.listen(3000);
express應用程序選項能夠經過app.set()
進行設置,經過app.get()
讀取如下是支持的選項
trust proxy
說明app位於front-facing proxy以後,X-Forwarded-*
報頭能夠用來肯定客戶端鏈接和IP地址。須要注意的是X-Forwarded-*
報頭很容易造假,因此檢測到的IP地址並不可靠。
trust proxy默認是禁止的。當激活時,express嘗試獲取經過front-facing proxy鏈接的客戶端IP地址。req.ips
屬性包含客戶端鏈接中的IP地址。一下只能夠用於設置:
Type | Value |
---|---|
Boolean | 若是是true,express假設客戶端IP地址是X-Forwarded-*中最左的值。若是false,express認爲直接鏈接客戶端,req.connection.remoteAddress是客戶端地址,默認值爲false。 |
IP 地址 | 可信任的ip地址,子網或者IP地址數組。如下是預約義子網名字
IP地址能夠以下設置 app.set('trust proxy', 'loopback'); // specify a single subnet app.set('trust proxy', 'loopback, 123.123.123.123'); // subnet and an address app.set('trust proxy', 'loopback, linklocal, uniquelocal'); app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); When specified, the IP addresses or the subnets are excluded from the address determination process, and the untrusted IP address nearest to the application server is determined as the client's IP address. |
Number | Trust the nth hop from the front-facing proxy server as the client. |
Function | 自定義信任實現。只有你知道本身在作什麼的時候才這樣作 app.set('trust proxy', function (ip) { if (ip === '127.0.0.1' || ip === '123.123.123.123') { return true; // trusted IPs } else { return false; } }); |
查看proxy-addr更多信息。
env
環境模式,默認爲process.env.NODE_ENV
(NODE_ENV環境變量)或者development
subdomain offset
The number of dot-separated parts of the host to remove to access subdomain, two by default.jsonp callback name
修改json回調名字?callback=
json replacer
JSON replacer callback, 默認爲nulljson spaces
設置爲JSON縮進,默認禁止case sensitive routing
enable區分大小寫,默認不區分,即/Foo
與/foo
同樣strict routing
enable嚴格路由,默認狀況下/foo
和/foo/
認爲相同view cache
設置模板編譯緩存,發佈狀況下默認激活view engine
引擎默認後綴名views
視圖目錄路徑,默認爲process.cwd() + '/views'
query parser
query解析器,simple
或者extended
,默認爲extended
,簡單query解析器基於node的原生解析器querystring
,擴展解析器基於qs x-powered-by
激活X-Powered-By: Express
HTTP報頭,默認激活etag
設置ETag響應頭
Type | Value |
---|---|
Boolean | true容許強ETag。這是默認設置。false禁止ETag |
String | 若是是`strong`使用強ETag。若是是`weak`使用弱ETag |
Function | 自定義ETag實現。只有你知道在作什麼才使用它 app.set('etag', function (body, encoding) { return generateHash(body, encoding); }); |
爲程序name設置value
app.set('title', 'My site'); app.get('title'); // My site
獲取設置的name值
app.get('title'); // undefined app.set('title', 'My site'); app.get('title'); // My site
設置name屬性爲true
app.enable('trust proxy'); app.get('trust proxy'); // true
檢查name是否激活
app.enabled('trust proxy'); // false app.enable('trust proxy'); app.enabled('trust proxy'); // true
設置name值爲false
app.disable('trust proxy'); app.get('trust proxy'); // false
檢查name是否禁止
app.disabled('trust proxy'); // true app.enable('trust proxy'); app.disabled('trust proxy'); // false
在path路徑Mount中間件函數。若是path沒有設置,默認爲/
.
中間件mount到path以後當請求路徑的起始部分匹配了path就會執行中間件。
因爲path默認值爲/
因此默認狀況下全部的請求都會執行中間件
// 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 it app.use(function (req, res, nex) { res.send('hello world'); }); // request will never reach this route app.get('/', function (req, res) { res.send('Welcome'); });
path
可使一個字符串,一個模式,一種正則表達式或者包含三種模式描述路徑的數組。
Type | Example |
---|---|
Path | // will match paths starting with /abcd app.use('/abcd', function (req, res, next) { next(); }); |
Path Pattern | // will match paths starting with /abcd and /abd app.use('/abc?d', function (req, res, next) { next(); }); // will match paths starting with /abcd, /abbcd, /abbbbcd and so on app.use('/ab+cd', function (req, res, next) { next(); }); // will match paths starting with /abcd, abxcd, /abfoocd and so on app.use('/ab*cd', function (req, res, next) { next(); }); // will match paths starting with /ad and abcd app.use('/a(bc)?d', function (req, res, next) { next(); }); |
Regular Expression | // will match paths starting with /abc and /xyz app.use(/\/abc|\/xyz/, function (req, res, next) { next(); }); |
Array | // will match paths starting with /abcd, /xyza, /lmn, and /pqr app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) { next(); }); |
function
可使一箇中間件函數,或者一系列中間件函數,或者包含中間件函數的數組或者他們的組合。因爲路由和程序都實現了中間件接口,能夠再其餘地方像使用中間件那樣使用。
Usage | Example |
---|---|
Single Middleware | 中間件函數能夠定義,而且在本地mount app.use(function (req, res, next) { next(); }); 路由也是合法的中間件 var router = express.Router(); router.get('/', function (req, res, next) { next(); }); app.use(router); express應用程序也是合法中間件 var subApp = express(); subApp.get('/', function (req, res, next) { next(); }); app.use(subApp); |
Series of Middleware | 能夠再一個mount路徑使用多箇中間件 var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); app.use(r1, r2); |
Array | 將多箇中間件組裝到數組中,若是數組形式的中間件是第一個參數或者惟一參數,須要制定mount路徑 var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); app.use('/', [r1, r2]); |
combination | function mw1(req, res, next) { next(); } function mw2(req, res, next) { next(); } var r1 = express.Router(); r1.get('/', function (req, res, next) { next(); }); var r2 = express.Router(); r2.get('/', function (req, res, next) { next(); }); var subApp = express(); subApp.get('/', function (req, res, next) { next(); }); app.use(mw1, [mw2, r1, r2], subApp); |
如下是一些使用express.static中間件的例子。
從public
目錄提供靜態文件服務
// GET /styles.css etc app.use(express.static(__dirname + '/public'));
將中間件mount到/static
路徑,這樣只有請求路徑以/static
開頭才響應。
// GET /static/style.css etc. app.use('/static', express.static(__dirname + '/public'));
禁止靜態文靜請求log:將log中間件配置到靜態文件中間件以後
app.use(express.static(__dirname + '/public')); app.use(logger());
在多個不一樣目錄提供靜態文件服務,放在最前面的具備最高優先級
app.use(express.static(__dirname + '/public')); app.use(express.static(__dirname + '/files')); app.use(express.static(__dirname + '/uploads'));
爲指定後綴名模板指定模板引擎回調。
默認狀況,express使用require()
根據文件擴展名加載模板引擎。例如,若是渲染foo.jade
,express會內部執行如下操做,而且將回調進行緩存以提升性能。
app.engine('jade', require('jade').__express);
對於沒有提供.__express
接口的引擎,須要定義映射,好比下面的例子
app.engine('html', require('ejs').renderFile);
在上面的例子中EJS提供.renderFile()
方法實現express所須要的(path, options, callback)
函數簽名
映射邏輯到路由參數。例如當:user
在路由路徑中出現的時候,能夠經過爲路由提供req.user
映射用戶邏輯,或者針對參數進行驗證。
注意:
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 matches too'); res.end(); });
一下代碼展現callback的用法,這很大程度上相似於中間件。代碼根據參數嘗試獲取用戶信息,若是成功,賦值給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')); } }); });
app.METHOD()
方法爲express程序提供路由功能,其中METHOD爲HTTP方法或加強方法,使用小寫,例如app.get()
,app.post()
,app.patch()
。
express支持的方法有:
對於不能轉化爲合法JavaScript變量的方法,使用中括號訪問法如:
app['m-search']('/', function () {});
能夠設置多個回調,他們都相同,就像中間件同樣工做。惟一的不一樣時這些回調能夠經過調用next('route')
跳過剩餘的路由回調函數。這種方法能夠用於執行條件路由,而後將控制傳遞給後續路由。
下面的代碼展現最簡單的路由定義。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 () { // ... });
若是有多個通用中間件,可使用route API中的all
var middleware = [loadForum, loadThread]; app.route('/forum/:fid/thread/:tid') .all(loadForum) .all(loadThread) .get(function () {}) .post(function () {});
這個方法相似於app.METHOD()
不一樣的是,它能夠匹配全部HTTP方法。
這個方法對於執行全局邏輯或者針對知足特定前綴的路徑很是有用。例如若是你將如下路由放在全部路由定義以前,這就會強制全部路徑訪問都進行驗證,而且自動加載用戶。須要注意的是這種回調不該該終止請求,loadUser
執行操做以後調用next()
傳遞控制權給下一個中間件。
app.all('*', requireAuthentication, loadUser);
與下面等價
app.all('*', requireAuthentication); app.all('*', loadUser);
另外一種用法是對特定路徑執行指定任務如:
app.all('/api/*', requireAuthentication);
返回一個路由實例,能夠用戶處理HTTP請求。使用app.route()
是避免屢次重複路徑的推薦方法
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) { // may be add a new event.. });
用於設置提供給程序全部模板的變量。對於爲模板提供輔助函數和app-level數據很是有用
app.locals.title = 'My App'; app.locals.strftime = require('strftime'); app.locals.email = 'me@myapp.com';
app.locals
是一個JavaScript對象。其屬性會被設置爲app局部變量
app.locals.title // => 'My App' app.locals.email // => 'me@myapp.com'
默認狀況下。express值暴露一個app-level級別變量:settings
app.set('title', 'My App'); // use settings.title in a view
使用回調函數渲染view
,這是app-level的res.render()
app.render('email', function (err, html) { // ... }); app.render('email', {name: 'Tibi'}, function (err, html) { // ... });
在指定主機,端口綁定並監聽。這個方法與node的http.Server#listen()相同
var express = require('express'); var app = express(); app.listen(3000);
express()
返回的app
是一個JavaScript Function
,能夠傳遞給node的HTTP服務器做爲回調來處理請求。這樣就支持同時提供同一份代碼支持HTTP和HTTPS版本的app。
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);
The app.listen() method is a convenience method for the following (if you wish to use HTTPS or provide both, use the technique above):
app.listen = function () { var server = http.createServer(this); return server.listen.apply(server, arguments); };
返回app路徑
var app = express(); var blog = express(); var blogAdmin = express(); app.use('/blog', blog); blog.use('/admin', blogAdmin); console.log(app.path()); // '' console.log(blog.path()); // '/blog' console.log(blogAdmin.path()); // '/blog/admin'
當app具備複雜的mount時。這個方法將變得複雜,一次推薦使用req.baseUrl
來獲取路徑
返回子app mount的路徑或者模式
var admin = express(); admin.get('/', function (req, res) { console.log(admin.mountpath); // /admin res.send('Admin Homepage'); }); app.use('/admin', admin); // mount the sub app
這個屬性與req.baseUrl
相似,不一樣的是app.mountpath
返回模式。
若是子app在多個路徑mustache上進行了mount。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*t res.send('Admin Secret'); }); admin.use('/secr*t', secret); app.use(['/adm*n', '/manager'], admin);
在子app上監聽mount
事件,當它被父app mount的時候觸發。父app做爲參數傳遞給回調函數。
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);
這個屬性是包含路由參數映射的對象,例如若是使用/user/:name
進行路由,req.params.name
上就設置了name
屬性。req.params
默認值爲{}
// GET /user/tj req.params.name // => 'tj'
當路由定義使用正則表達式時,捕獲分組將出如今req.params[N]
數組對應元素,其中N是底n個捕獲組。這個規則可使用在未知的匹配狀況下,如/file/*
// GET /file/js/jquery.js req.params[0]; // => 'js/jquery.js'
保存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'
包含請求體解析後數據的鍵值對。默認爲undefined
,經過使用解析中間件渲染後獲得對應值,常見中間件爲body-parser和multer
下面的例子展現使用body-parser中間件來渲染req.body
var app = require('express')(); var bodyParser = require('body-parser'); var multer = require('multer'); app.use(bodyParser.json()); // for parsing application/json app.use(bodyParser.urlencoded({extended: true})); // for parsing application/x-www-from-urlencoded app.use(multer()); // for parsing multipart/form-data app.post('/', function (req, res) { console.log(req.body); res.json(req.body); });
返回name
對應的參數值。
// ?name=tobi req.param('name'); // => 'tobi' // POST name=tobi req.param('name'); // => 'tobi' // user/tobi for /user/:name req.param('name'); // => 'tobi'
查詢順序以下:
能夠指定defaultValue
,當參數名沒有查找到的時候的默認值。
一般來講,最好的方法是直接查詢對應對象尋找值。
返回當前匹配的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 } }
須要cookieParser()
中間件來解析,生成用戶代理包含cookie的鍵值對,默認爲{}
。
// cookie: name=tj req.cookies.name // => 'tj'
參考cookie-parser更多信息。
使用cookieParser(secret)
渲染對象。 It contains signed cookies sent by the user-agent, unsigned and ready for use. Signed cookies reside in a different object to show developer intent; otherwise, a malicious attack could be placed on req.cookie values (which are easy to spoof). Note that signing a cookie does not make it "hidden" or encrypted; this simply prevents tampering (because the secret used to sign is private). If no signed cookies are sent, it defaults to {}.
// Cookie: user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 req.signedCookies.user // => "tobi"
參考cookie-parser查詢更多信息。
讀取不區分大小寫的請求頭首部。Referrer
和Referer
等價。
req.get('Content-Type'); // => 'text/plain' req.get('content-type'); // => 'text/plain' req.get('something'); // => undefined
此方法等價於req.header(field)
檢查給定types
是否可接受(acceptable),當能夠接受的時候返回最佳匹配項,若是不匹配,返回undefined
(此時可使用406 Not Acceptable
)。
type
值多是單個MIME type字符串如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'
查看accepts尋找更多信息。
檢測制定charset是否可接受
檢測制定lang是否可接受
檢測指定encoding是否可接受
檢測請求的Content-Type
是否匹配指定的MIME類型。
// 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
查看type-is尋找更多信息。
返回遠程地址(或者trust proxy
激活時,upstream address)
req.ip; // => '127.0.0.1'
當trust proxy
爲true
,解析X-Forwarded-For
獲取ip地址列表,不然值爲空數組。
返回請求URL的pathname
// example.com/users?sort=desc req.path // => '/users'
返回Host頭包含的hostname值
// Host: example.com:3000 req.hostname // => example.com
檢測請求是否新鮮。(Last-Modified
或者ETag
是否匹配)
req.fresh // => true
查看fresh尋找更多信息
檢查請求是否stales
(Last-Modified
和ETag
是否匹配)
req.stale // => true
檢查X-Requested-With
查看是否經過XMLHttpRequest
發送
req.xhr // => true
Return the protocol string "http" or "https" when requested with TLS. If the "trust proxy" setting is enabled, the "X-Forwarded-Proto" header field will be trusted. If you're running behind a reverse proxy that supplies https for you, this may be enabled.
req.protocol // => http
Check if a TLS connection is established. This is a short-hand for:
'https' == req.protocol;
返回包含子域名的數組
// Host: tobi.ferrets.example.com req.subdomains // => ['ferrets', 'tobi']
包含原始的請求url,req.url
包含的是去掉mount以後的路徑
// GET /search?q=something req.originalUrl // => /search?q=something
This property refers to the URL path, on which a router instance was mounted.
var greet = express.Router(); greet.get('jp', function (req, res) { console.log(req.baseUrl); // /greet res.send('Konichiwa!'); }); app.use('/greet', greet); // load the router on '/greet'
若是mount使用的是模式。取值的時候獲取的不是模式,是具體值
// load the router on '/gre+t' and '/hel{2}o' app.use(['/gre+t', '/hel{2}o'], greet);
請求/greet/jp
時,baseUrl爲/greet,請求/hello/jp時baseUrl爲/hello
req.baseUrl is similar to the mountpath property of the app object, except app.mountpath returns the matched path pattern(s).
node的res.statusCode
等價。用於設置HTTP響應狀態碼。
res.status(403).end(); res.status(400).send('Bad Request'); res.status(404).sendFile('/absolute/path/to/404.png');
設置響應頭field值,或者傳遞對象設置多個field。
res.set('Content-Type', 'text/plain'); res.set({ 'Content-Type': 'text/plain', 'Content-Length': '123', 'ETag': '12345' });
與res.header(field, [value])
等價。
讀取不區分大小寫的響應頭field
res.get('Content-Type'); // => 'text/plain'
設置cookiename
爲value
。value
能夠是字符串或者對象,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 });
這種方法也能夠設置signed cookie。只須要設置signed
選項。When given res.cookie() will use the secret passed to cookieParser(secret) to sign the value.
res.cookie('name', 'tobi', { signed: true });
而後經過訪問req.signedCookie
獲取信息
清除cookie name對應的值,path默認爲/
res.cookie('name', 'tobi', { path: '/admin' }); res.clearCookie('name', { path: '/admin' });
express將設置的url字符串直接設置到
Location
頭部,不進行驗證。瀏覽器讀取該頭部並進行重定向
設置重定向url,狀態碼默認爲302.
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
設置重定向url爲/admin
會重定向到http://example.com/admin
res.redirect('/admin');
重定向能夠相對於當前URL,從http://example.com/blog/admin/
(注意末尾的斜線)重定向到post/new
獲得的最終地址爲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('..');
也能夠經過設置重定向實現後退效果。express使用referer進行設置,若是沒有這個值,使用默認值/
res.redirect('back');
設置location報頭
res.location('/foo/bar'); res.location('foo/bar'); res.location('http://example.com'); res.location('../login'); res.location('back');
這裏的url規則和res.redirect()
相同
發送響應
res.send(new Buffer('whoop')); res.send({some: 'json'}); res.send('<p>some html</p>'); res.status(404).send('sorry, can not find it'); res.status(500).send({error: 'something blew up'});
這個函數對於非流式響應會自動設置Content-Length
(沒有在其餘地方設置時)而且提供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>');
返回數組或者對象時,默認設置JSON
res.send({user: 'tobi'}); res.send([1, 2, 3]);
返回json響應,參數爲對象或者數組時與res.send()
等價。對於其餘狀況下使用這個方法能夠明確設置對應報頭。
res.json(null); res.json({user: 'tobi'}); res.status(500).json({error: 'message'});
返回一個JSONP響應。使用方法與res.json()
相同,不一樣的是返回結果會加上回調函數名字以支持JSONP,默認函數名爲callback
,能夠經過app.set('jsonp callback name', 'aaa')
設置與請求約定的回調名參數。
res.jsonp(null); res.jsonp({ user: 'tobi' }); res.status(500) .jsonp( { error: 'message' });
// ?callback=foo res.jsonp({user: 'tobi'}); // => foo({'user': 'tobi'}) app.set('jsonp callback name', 'cb'); // ?cb=foo res.status(500).jsonp({error: 'message'}); // => foo({'error': 'message'})
設置Content-Type
,根據後綴名查詢對應值,若是包含/
那直接設置爲對應結果。
res.type('.html'); res.type('html'); res.type('json'); res.type('application/json'); res.type('png');
太長不想翻了查看res.format(object)
設置Content-Disposition
報頭爲attachment
,若是指定了filename,Content-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
須要express版本高於4.8.0
設置HTTP狀態碼而且將響應體設置爲對應描述字符
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')
若是設置了位置狀態碼。HTTP狀態碼也會設置爲指定值,描述字符串也於指定值相同
res.sendStatus(2000); // res.status(2000).send('2000');
設置下載res.download()
設置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"
設置本地變量,只能在請求/響應週期內的視圖渲染可見。具體操做與app.locals相同
這個對象在暴露請求級別信息時很是有用,如請求路徑名,驗證信息,用戶設置等。
app.use(function (req, res, next) { res.locals.user = req.user; res.locals.authenticated = !req.user.anonymous; next(); });
渲染指定的視圖,出現錯誤時內部調用next(err)
。提供的回調函數會產地錯誤和渲染後的字符串做爲參數,此時不會自動發送響應。
res.render('index', function (err, html) { // ... }); res.render('user', {name: 'Tobi'}, function (err, html) { // ... });
在響應報頭沒有設置的狀況下添加該報頭。
res.vary('User-Agent').render('docs');
繼承自node的http.serverResponse
,用於結束響應。惟一推薦的用處是不發送數據而快速結束響應。若是想要發送數據,推薦使用res.send()
,res.json()
等。
res.end(); res.status(404).end();
用於檢測HTTP投是否已經發送
app.get('/', function (req, res) { console.log(res.headersSent); // false res.send('OK'); console.log(res.headersSent); // true });
路由是Router或者中間件的實例。路由能夠看作微型應用,智能用於執行中間件和路由函數。每個express應用程序有一個內置的app router。
路由表現上與中間件類似,能夠在app或者其餘路由上經過.user()
進行使用。
一下方法建立一個路由:
var router = express.Router([options]);
可選的選項能夠修改路由行爲
caseSensitive
強制區分大小寫。默認不區分,/Foo
與/foo
同樣strict
激活嚴格路由,默認狀況下/foo
和/foo/
認爲相同mergeParams
,默認值爲false
確保來自父路由的req.params
獲得保留。若是父路由和子路由有參數衝突。子路由參數優先級更高。// invoked for any requrests passed to this router router.use(function (req, res, next) { // .. some logic here.. like any other middleware next(); }); // will handle any request that ends in /events // depends on where the router is user() router.get('/events', function (req, res, next) { // .. });
能夠將路由設置到對應的url上針對特定url進行響應
// only requests to /calendar/* will be sent to our router app.use('/calendar', router);
相似於app.use()
使用中間件處理請求。mount路徑默認爲'/'
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 middleware router.use(function (req, ers, next) { router.log('%s % %s', req.method, req.url, req.path); next(); }); // this will only be invoked if the path starts with /bar front the mount point router.use('/bar', function (req, res, next) { // maybe some additional operation next(); }); // always invoked router.use(function (req, res, next) { res.send('Hello World'); }); app.use('/foo', router); app.listen(3000);
mount路徑在傳遞給中間件時會自動去掉。這樣產生的效果是中間件能夠不關心具體路徑前綴。
router.use()
註冊中間件的順序很是重要,全部中間件按照順序調用。
var logger = require('morgan'); router.use(logger()); router.use(express.static(__dirname + '/public')); router.use(function (req, res) { res.send('Hello'); });
假設想要忽略靜態文件的log,可是後續的中間件須要日誌。能夠將靜態文件中間件放到前面。
router.use(express.static(__dirname + '/public')); router.use(logger()); router.use(function (req, res) { res.send('Hello'); });
另外一個使用場景是在多個目錄提供靜態文件訪問。express會按照順序遍歷目錄來提供文件。
app.use(express.static(__dirname + '/public')); app.use(express.static(__dirname + '/files'));
爲路由參數映射邏輯。例如:user
出如今路由路徑的時候能夠映射用戶加載和驗證操做。
在一個請求響應週期中回調函數只執行一次,即便參數匹配多個路由
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 thsi matches too'); res.end(); });
回調函數與中間件相似,可是多了一個參數,用於對應請求實際參數。也能夠從req.params
獲取,能夠加載用戶以後添加到req.user
進行保存
返回對應路徑的一個路由實例,而後針對路由設置不一樣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 }) .get(function (req, res, next) { res.json(req.user); }) .put(function (req, res, next) { // just an example of maybe updating the user req.user.name = req.params.name; // save user ... etc res.json(req.user); }) .post(function (req, res, next) { next(new Error('not implemented')); }) .delete(function (req, res, next) { next(new Error('not implemented')); });
經過以上方法能夠重用/users/:user_id
來添加多個HTTP方法響應
爲路由制定HTTP方法響應處理。
爲路由制定響應全部HTTP方法的中間件
這個問題沒有肯定的答案。取決於你程序的規模和開發團隊。爲了達到儘可能的靈活,Express不對結構進行假設。
路由和其餘程序相關的邏輯能夠根據你的喜愛放到任意目錄和文件中。能夠查看下面的例子來得到靈感:
一樣存在一些第三方擴展,用於簡化模式
express沒有數據庫的概念。這徹底交給第三方模塊,這樣容許你與任何數據庫交互。
能夠查看LoopBack
Express沒有限制,你可使用你但願的任意方法。這裏是一個簡單的用戶名/密碼模式:查看例子
express支持全部符合(path, locals, callback)
簽名的模板引擎。若是想規格化模板引擎接口和緩存,查看consolidate.js。
一般能夠屢次使用任意的中間件。以下代碼中,若是請求GET /js/jquery.js
在./public/js/jquery.js
沒有找到,它繼續嘗試./files/js/jquery.js
app.use(express.static('public')); app.use(express.static('files'));
connect的"mounting"特性容許你定義路徑前綴。這樣就好像前綴字符串沒有出如今路徑中同樣。假設你須要訪問GET /files/js/jquery.js
。你能夠在/files
目錄mount中間件,暴露/js/jquery.js
做爲url。代碼以下:
app.use('/files', express.static('public'));
express中,404不是錯誤的結果。所以,錯誤處理中間件不會捕獲404.由於404代表還有工做沒有完成,也就是說,express執行了全部中間件/路由,可是沒有找到對應的響應處理。你須要在末尾添加一箇中間件來處理404:
app.use(function (req, res, next) { res.send(404,, 'Sorry can not find that'); });
像定義其餘中間件同樣定義錯誤處理程序。惟一的區別是這個程序指望參數爲四個(err, req, res, next)
,查看錯誤處理尋找更多信息。
app.use(function (err, req, res, next) { console.error(err.stack); res.send(500, 'something broke'); });