Express 4 是對(duì) Express 3 的一個(gè)顛覆性改變,也就是說(shuō)如果您更新了 Express, Express 3 應(yīng)用會(huì)無(wú)法工作。
該章包含如下內(nèi)容:
Express 4 的主要變化如下:
其他變化請(qǐng)參考:
Express 4 不再依賴(lài) Connect,而且從內(nèi)核中移除了除 express.static
外的所有內(nèi)置中間件。也就是說(shuō)現(xiàn)在的 Express 是一個(gè)獨(dú)立的路由和中間件 Web 框架,Express 的版本升級(jí)不再受中間件更新的影響。
移除了內(nèi)置的中間件后,您必須顯式地添加所有運(yùn)行應(yīng)用需要的中間件。請(qǐng)遵循如下步驟:
npm install --save <module-name>
require('module-name')
app.use( ... )
下表列出了 Express 3 和 Express 4 中對(duì)應(yīng)的中間件。
Express 3 | Express 4 |
---|---|
express.bodyParser | body-parser +multer |
express.compress | compression |
express.cookieSession | cookie-session |
express.cookieParser | cookie-parser |
express.logger | morgan |
express.session | express-session |
express.favicon | serve-favicon |
express.responseTime | response-time |
express.errorHandler | errorhandler |
express.methodOverride | method-override |
express.timeout | connect-timeout |
express.vhost | vhost |
express.csrf | csurf |
express.directory | serve-index |
express.static | serve-static |
這里是 Express 4 的 所有中間件列表 。
多數(shù)情況下,您可以直接使用 Express 4 中對(duì)應(yīng)的中間件替換 Express 3 中的中間件,請(qǐng)參考 GitHub 中的模塊文檔了解更多信息。
app.use
可以接收參數(shù)了在 Express 4 中,可以從路由句柄中讀取參數(shù),以該參數(shù)的值作為路徑加載中間件,比如像下面這樣:
app.use('/book/:id', function(req, res, next) {
console.log('ID:', req.params.id);
next();
});
應(yīng)用現(xiàn)在隱式地加載路由中間件,因此不需要擔(dān)心涉及到 router
中間件對(duì)路由中間件加載順序的問(wèn)題了。
定義路由的方式依然未變,但是新的路由系統(tǒng)有兩個(gè)新功能能幫助您組織路由:
app.route()
,可以為路由路徑創(chuàng)建鏈?zhǔn)铰酚删浔?/li>express.Router
,可以創(chuàng)建可掛載的模塊化路由句柄。app.route()
方法新增加的 app.route()
方法可為路由路徑創(chuàng)建鏈?zhǔn)铰酚删浔?。由于路徑在一個(gè)地方指定,會(huì)讓路由更加模塊化,也能減少代碼冗余和拼寫(xiě)錯(cuò)誤。請(qǐng)參考 Router()
文檔 獲取更多關(guān)于路由的信息。。
下面是一個(gè)使用 app.route()
方法定義鏈?zhǔn)铰酚删浔睦印?/p>
app.route('/book')
.get(function(req, res) {
res.send('Get a random book');
})
.post(function(req, res) {
res.send('Add a book');
})
.put(function(req, res) {
res.send('Update the book');
});
express.Router
類(lèi)另外一個(gè)幫助組織路由的是新加的 express.Router
類(lèi),可使用它創(chuàng)建可掛載的模塊化路由句柄。Router
類(lèi)是一個(gè)完整的中間件和路由系統(tǒng),鑒于此,人們常稱(chēng)之為“迷你應(yīng)用”。
下面的例子創(chuàng)建了一個(gè)模塊化的路由,并加載了一個(gè)中間件,然后定義了一些路由,并且在主應(yīng)用中將其掛載到指定路徑。
在應(yīng)用目錄下創(chuàng)建文件 birds.js
,其內(nèi)容如下:
var express = require('express');
var router = express.Router();
// 特針對(duì)于該路由的中間件
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
// 定義網(wǎng)站主頁(yè)的路由
router.get('/', function(req, res) {
res.send('Birds home page');
});
// 定義 about 頁(yè)面的路由
router.get('/about', function(req, res) {
res.send('About birds');
});
module.exports = router;
然后,在應(yīng)用中加載該路由:
var birds = require('./birds');
...
app.use('/birds', birds);
應(yīng)用現(xiàn)在就可以處理發(fā)送到 /birds
和 /birds/about
的請(qǐng)求,并且會(huì)調(diào)用特針對(duì)于該路由的 timeLog
中間件。
下表列出了 Express 4 中其他一些盡管不大,但是非常重要的變化。
對(duì)象 | 描述 |
---|---|
Node | >Express 4 需要 Node 0.10.x 或以上版本,已經(jīng)放棄了對(duì) Node 0.8.x 的支持。 |
|
|
| 已經(jīng)刪除 |
| Express 4 默認(rèn)禁用 |
| 使用 |
| 不再解析相對(duì) URLs。 |
| 從數(shù)組變?yōu)閷?duì)象。 |
| 從函數(shù)變?yōu)閷?duì)象。 |
| 變?yōu)? |
| 變?yōu)? |
| 已刪除。 |
| 已刪除。 |
| F功能僅限于設(shè)置基本的 cookie 值,使用 |
下面是一個(gè)從 Express 3 遷移到 Express 4 的例子,請(qǐng)留意 app.js
和 package.json
。
app.js
請(qǐng)看如下 Express 3 應(yīng)用,其 app.js
文件內(nèi)容如下:
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var app = express();
// 適用開(kāi)發(fā)和生產(chǎn)環(huán)境
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.methodOverride());
app.use(express.session({ secret: 'your secret here' }));
app.use(express.bodyParser());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// 只針對(duì)開(kāi)發(fā)環(huán)境
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
package.json
相對(duì)應(yīng)的 package.json
文件內(nèi)容如下:
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.12.0",
"jade": "*"
}
}
首先安裝 Express 4 應(yīng)用需要的中間件,使用如下命令將 Express 和 Jade 更新至最新版本:
$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest jade@latest --save
按如下方式修改 app.js
文件:
這些內(nèi)置中間件 express.favicon
, express.logger
, express.methodOverride
, express.session
, express.bodyParser
and express.errorHandler
在 express
對(duì)象中已經(jīng)沒(méi)有了,您必須手動(dòng)安裝相應(yīng)的中間件,并在應(yīng)用中加載它們。
不需要加載 app.router
,它不再是一個(gè)合法的 Express 4 對(duì)象,刪掉 app.use(app.router);
。
確保加載中間件的順序正確,加載完應(yīng)用路由后再加載 errorHandler
。
package.json
運(yùn)行上述 npm
命令后,會(huì)將 package.json
文件更新為:
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"body-parser": "^1.5.2",
"errorhandler": "^1.1.1",
"express": "^4.8.0",
"express-session": "^1.7.2",
"jade": "^1.5.0",
"method-override": "^2.1.2",
"morgan": "^1.2.2",
"multer": "^0.1.3",
"serve-favicon": "^2.0.1"
}
}
app.js
然后刪掉無(wú)效的代碼,加載需要的中間件,再做一些必要的修改,新的 app.js
內(nèi)容如下:
var http = require('http');
var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var methodOverride = require('method-override');
var session = require('express-session');
var bodyParser = require('body-parser');
var multer = require('multer');
var errorHandler = require('errorhandler');
var app = express();
// 適用開(kāi)發(fā)和生產(chǎn)環(huán)境
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(methodOverride());
app.use(session({ resave: true,
saveUninitialized: true,
secret: 'uwotm8' }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(multer());
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', routes.index);
app.get('/users', user.list);
// 錯(cuò)誤處理中間件應(yīng)當(dāng)在路由加載之后才能加載
if ('development' == app.get('env')) {
app.use(errorHandler());
}
var server = http.createServer(app);
server.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
除非需要直接使用 http
模塊(socket.io/SPDY/HTTPS),否則不必加載它,可使用如下方式啟動(dòng)應(yīng)用:
app.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
遷移完成后,應(yīng)用就變成了 Express 4 應(yīng)用。為了確保遷移成功,使用如下命令啟動(dòng)應(yīng)用:
$ node .
輸入 http://localhost:3000 即可看到經(jīng)由 Express 4 渲染的主頁(yè)。
生成 Express 應(yīng)用的命令行還是 express
,為了升級(jí)到最新版本,您必須首先卸載 Express 3 的應(yīng)用生成器,然后安裝新的 express-generator
。
如果您已經(jīng)安裝了 Express 3 應(yīng)用生成器,請(qǐng)使用如下命令卸載:
$ npm uninstall -g express
根據(jù)您的文件目錄權(quán)限,您可能需要以 sudo
權(quán)限執(zhí)行該命令。
然后安裝新的生成器:
$ npm install -g express-generator
根據(jù)您的文件目錄權(quán)限,您可能需要以 sudo
權(quán)限執(zhí)行該命令。
現(xiàn)在系統(tǒng)的 express
命令就升級(jí)為 Express 4 應(yīng)用生成器了。
除如下選項(xiàng)外,大部分命令參數(shù)和使用方法都維持不變:
--sessions
o選項(xiàng)。--jshtml
選項(xiàng)。--hogan
選項(xiàng)以支持 Hogan.js。運(yùn)行下述命令創(chuàng)建一個(gè) Express 4 應(yīng)用:
$ express app4
如果查看 app4/app.js
的內(nèi)容,會(huì)發(fā)現(xiàn)應(yīng)用需要的所有中間件(不包括 express.static
)都作為獨(dú)立模塊載入,而且再不顯式地加載 router
中間件。
您可能還會(huì)發(fā)現(xiàn),和舊的生成器生成的應(yīng)用相比, app.js
現(xiàn)在成了一個(gè) Node 模塊。
安裝完依賴(lài)后,使用如下命令啟動(dòng)應(yīng)用:
$ npm start
如果看一看 package.json
文件中的 npm 啟動(dòng)腳本,會(huì)發(fā)現(xiàn)啟動(dòng)應(yīng)用的真正命令是 node ./bin/www
,在 Express 3 中則為 node app.js
。
Express 4 應(yīng)用生成器生成的 app.js
是一個(gè) Node 模塊,不能作為應(yīng)用(除非修改代碼)單獨(dú)啟動(dòng),需要通過(guò)一個(gè) Node 文件加載并啟動(dòng),這里這個(gè)文件就是 node ./bin/www
。
創(chuàng)建或啟動(dòng) Express 應(yīng)用時(shí),bin
目錄或者文件名沒(méi)有后綴的 www
文件都不是必需的,它們只是生成器推薦的做法,請(qǐng)根據(jù)需要修改。
如果不想保留 www
,想讓?xiě)?yīng)用變成 Express 3 的形式,則需要?jiǎng)h除 module.exports = app;
,并在 app.js
末尾粘貼如下代碼。
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function() {
debug('Express server listening on port ' + server.address().port);
});
記得在 app.js
上方加入如下代碼加載 debug
模塊。
var debug = require('debug')('app4');
然后將 package.json
文件中的 "start": "node ./bin/www"
修改為 "start": "node app.js"
。
現(xiàn)在就將 ./bin/www
的功能又改回到 app.js
中了。我們并不推薦這樣做,這個(gè)練習(xí)只是為了幫助大家理解 ./bin/www
是如何工作的,以及為什么 app.js
不能再自己?jiǎn)?dòng)。
更多建議: