Express 4 是對 Express 3 的一個顛覆性改變,也就是說如果您更新了 Express, Express 3 應用會無法工作。
該章包含如下內(nèi)容:
Express 4 的主要變化如下:
其他變化請參考:
Express 4 不再依賴 Connect,而且從內(nèi)核中移除了除 express.static
外的所有內(nèi)置中間件。也就是說現(xiàn)在的 Express 是一個獨立的路由和中間件 Web 框架,Express 的版本升級不再受中間件更新的影響。
移除了內(nèi)置的中間件后,您必須顯式地添加所有運行應用需要的中間件。請遵循如下步驟:
npm install --save <module-name>
require('module-name')
app.use( ... )
下表列出了 Express 3 和 Express 4 中對應的中間件。
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 中對應的中間件替換 Express 3 中的中間件,請參考 GitHub 中的模塊文檔了解更多信息。
app.use
可以接收參數(shù)了在 Express 4 中,可以從路由句柄中讀取參數(shù),以該參數(shù)的值作為路徑加載中間件,比如像下面這樣:
app.use('/book/:id', function(req, res, next) {
console.log('ID:', req.params.id);
next();
});
應用現(xiàn)在隱式地加載路由中間件,因此不需要擔心涉及到 router
中間件對路由中間件加載順序的問題了。
定義路由的方式依然未變,但是新的路由系統(tǒng)有兩個新功能能幫助您組織路由:
app.route()
,可以為路由路徑創(chuàng)建鏈式路由句柄。express.Router
,可以創(chuàng)建可掛載的模塊化路由句柄。app.route()
方法新增加的 app.route()
方法可為路由路徑創(chuàng)建鏈式路由句柄。由于路徑在一個地方指定,會讓路由更加模塊化,也能減少代碼冗余和拼寫錯誤。請參考 Router()
文檔 獲取更多關于路由的信息。。
下面是一個使用 app.route()
方法定義鏈式路由句柄的例子。
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
類另外一個幫助組織路由的是新加的 express.Router
類,可使用它創(chuàng)建可掛載的模塊化路由句柄。Router
類是一個完整的中間件和路由系統(tǒng),鑒于此,人們常稱之為“迷你應用”。
下面的例子創(chuàng)建了一個模塊化的路由,并加載了一個中間件,然后定義了一些路由,并且在主應用中將其掛載到指定路徑。
在應用目錄下創(chuàng)建文件 birds.js
,其內(nèi)容如下:
var express = require('express');
var router = express.Router();
// 特針對于該路由的中間件
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
// 定義網(wǎng)站主頁的路由
router.get('/', function(req, res) {
res.send('Birds home page');
});
// 定義 about 頁面的路由
router.get('/about', function(req, res) {
res.send('About birds');
});
module.exports = router;
然后,在應用中加載該路由:
var birds = require('./birds');
...
app.use('/birds', birds);
應用現(xiàn)在就可以處理發(fā)送到 /birds
和 /birds/about
的請求,并且會調(diào)用特針對于該路由的 timeLog
中間件。
下表列出了 Express 4 中其他一些盡管不大,但是非常重要的變化。
對象 | 描述 |
---|---|
Node | >Express 4 需要 Node 0.10.x 或以上版本,已經(jīng)放棄了對 Node 0.8.x 的支持。 |
|
|
| 已經(jīng)刪除 |
| Express 4 默認禁用 |
| 使用 |
| 不再解析相對 URLs。 |
| 從數(shù)組變?yōu)閷ο蟆?/p> |
| 從函數(shù)變?yōu)閷ο蟆?/p> |
| 變?yōu)? |
| 變?yōu)? |
| 已刪除。 |
| 已刪除。 |
| F功能僅限于設置基本的 cookie 值,使用 |
下面是一個從 Express 3 遷移到 Express 4 的例子,請留意 app.js
和 package.json
。
app.js
請看如下 Express 3 應用,其 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();
// 適用開發(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')));
// 只針對開發(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
相對應的 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 應用需要的中間件,使用如下命令將 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
對象中已經(jīng)沒有了,您必須手動安裝相應的中間件,并在應用中加載它們。
不需要加載 app.router
,它不再是一個合法的 Express 4 對象,刪掉 app.use(app.router);
。
確保加載中間件的順序正確,加載完應用路由后再加載 errorHandler
。
package.json
運行上述 npm
命令后,會將 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
然后刪掉無效的代碼,加載需要的中間件,再做一些必要的修改,新的 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();
// 適用開發(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);
// 錯誤處理中間件應當在路由加載之后才能加載
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),否則不必加載它,可使用如下方式啟動應用:
app.listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
遷移完成后,應用就變成了 Express 4 應用。為了確保遷移成功,使用如下命令啟動應用:
$ node .
輸入 http://localhost:3000 即可看到經(jīng)由 Express 4 渲染的主頁。
生成 Express 應用的命令行還是 express
,為了升級到最新版本,您必須首先卸載 Express 3 的應用生成器,然后安裝新的 express-generator
。
如果您已經(jīng)安裝了 Express 3 應用生成器,請使用如下命令卸載:
$ 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
命令就升級為 Express 4 應用生成器了。
除如下選項外,大部分命令參數(shù)和使用方法都維持不變:
--sessions
o選項。--jshtml
選項。--hogan
選項以支持 Hogan.js。運行下述命令創(chuàng)建一個 Express 4 應用:
$ express app4
如果查看 app4/app.js
的內(nèi)容,會發(fā)現(xiàn)應用需要的所有中間件(不包括 express.static
)都作為獨立模塊載入,而且再不顯式地加載 router
中間件。
您可能還會發(fā)現(xiàn),和舊的生成器生成的應用相比, app.js
現(xiàn)在成了一個 Node 模塊。
安裝完依賴后,使用如下命令啟動應用:
$ npm start
如果看一看 package.json
文件中的 npm 啟動腳本,會發(fā)現(xiàn)啟動應用的真正命令是 node ./bin/www
,在 Express 3 中則為 node app.js
。
Express 4 應用生成器生成的 app.js
是一個 Node 模塊,不能作為應用(除非修改代碼)單獨啟動,需要通過一個 Node 文件加載并啟動,這里這個文件就是 node ./bin/www
。
創(chuàng)建或啟動 Express 應用時,bin
目錄或者文件名沒有后綴的 www
文件都不是必需的,它們只是生成器推薦的做法,請根據(jù)需要修改。
如果不想保留 www
,想讓應用變成 Express 3 的形式,則需要刪除 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
中了。我們并不推薦這樣做,這個練習只是為了幫助大家理解 ./bin/www
是如何工作的,以及為什么 app.js
不能再自己啟動。
更多建議: