鍍金池/ 教程/ HTML/ 遷移到 Express 4
在 Express 中使用模板引擎
代理之后的 Express
使用中間件
數(shù)據(jù)庫集成
錯誤處理
調(diào)試 Express
路由
遷移到 Express 4

遷移到 Express 4

概覽

Express 4 是對 Express 3 的一個顛覆性改變,也就是說如果您更新了 Express, Express 3 應(yīng)用會無法工作。

該章包含如下內(nèi)容:

  • Express 4 的變化。
  • 一個從 Express 3 遷移到 Express 4 的示例。
  • 遷移到 Express 4 應(yīng)用生成器。

Express 4 的變化

Express 4 的主要變化如下:

  • 對 Express 內(nèi)核和中間件系統(tǒng)的改進。不再依賴 Connect 和內(nèi)置的中間件,您需要自己添加中間件。
  • 對路由系統(tǒng)的改進。
  • 其他變化。

其他變化請參考:

對 Express 內(nèi)核和中間件系統(tǒng)的改進

Express 4 不再依賴 Connect,而且從內(nèi)核中移除了除 express.static 外的所有內(nèi)置中間件。也就是說現(xiàn)在的 Express 是一個獨立的路由和中間件 Web 框架,Express 的版本升級不再受中間件更新的影響。

移除了內(nèi)置的中間件后,您必須顯式地添加所有運行應(yīng)用需要的中間件。請遵循如下步驟:

  1. 安裝模塊:npm install --save <module-name>
  2. 在應(yīng)用中引入模塊:require('module-name')
  3. 按照文檔的描述使用模塊:app.use( ... )

下表列出了 Express 3 和 Express 4 中對應(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 中對應(yīng)的中間件替換 Express 3 中的中間件,請參考 GitHub 中的模塊文檔了解更多信息。

app.use accepts parameters

在 Express 4 中,可以從路由句柄中讀取參數(shù),以該參數(shù)的值作為路徑加載中間件,比如像下面這樣:

app.use('/book/:id', function(req, res, next) {
  console.log('ID:', req.params.id);
  next();
});

路由系統(tǒng)

應(yīng)用現(xiàn)在隱式地加載路由中間件,因此不需要擔(dān)心中間件加載順序。

定義路由的方式依然未變,但是新的路由系統(tǒng)有兩個新功能能幫助您組織路由:

  • 新方法 app.route() 可以為路由路徑創(chuàng)建鏈式路由句柄。
  • 新類 express.Router 可以創(chuàng)建可掛載的模塊化路由句柄。

app.route() 方法

新增加的 app.route() 方法可為路由路徑創(chuàng)建鏈式路由句柄。由于路徑在一個地方指定,會讓路由更加模塊化,也能減少代碼冗余和拼寫錯誤。請參考 Router() 文檔獲取更多關(guān)于路由的信息。

下面是一個使用 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),鑒于此,人們常稱之為“迷你應(yīng)用”。

下面的例子創(chuàng)建了一個模塊化的路由,并加載了一個中間件,然后定義了一些路由,并且在主應(yīng)用中將其掛載到指定路徑。

在應(yī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();
});
// 定義主頁路由
router.get('/', function(req, res) {
  res.send('Birds home page');
});
// 定義 about 頁面路由
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 的請求,并且會調(diào)用特針對于該路由的 timeLog 中間件。

其他變化

下表列出了 Express 4 中其他一些盡管不大,但是非常重要的變化。

對象 描述
Node Express 4 需要 Node 0.10.x 或以上版本,已經(jīng)放棄了對 Node 0.8.x 的支持。

http.createServer()

http 模塊,除非您需要直接使用它(socket.io/SPDY/HTTPS),使用 app.listen() 啟動應(yīng)用。

app.configure()

已經(jīng)刪除 app.configure(),使用 process.env.NODE_ENV 或者 app.get('env') 檢測環(huán)境并配置應(yīng)用。

json spaces

Express 4 默認禁用 json spaces 屬性。

req.accepted()

使用 req.accepts()、 req.acceptsEncodings()、 req.acceptsCharsets()req.acceptsLanguages()。

res.location()

不再解析相對 URLs。

req.params

從數(shù)組變?yōu)閷ο蟆?/p>

res.locals

從函數(shù)變?yōu)閷ο蟆?/p>

res.headerSent

變?yōu)?res.headersSent。

app.route

變?yōu)?app.mountpath。

res.on('header')

已刪除。

res.charset

已刪除。

res.setHeader('Set-Cookie', val)

功能僅限于設(shè)置基本的 cookie 值,使用 res.cookie() 訪問更多功能。

遷移示例

下面是一個從 Express 3 遷移到 Express 4 的例子,請留意 app.jspackage.json。

Express 3 應(yīng)用

app.js

請看如下 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();

// 環(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ā)使用
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

相應(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 文件:

  1. express.favicon、express.logger、express.methodOverride、express.session、express.bodyParserexpress.errorHandler 這些內(nèi)置中間件在 express 對象中已經(jīng)沒有了,您必須手動安裝相應(yīng)的中間件,并在應(yīng)用中加載它們。
  2. 不需要加載 app.router,它不再是一個合法的 Express 4 對象,刪掉 app.use(app.router);
  3. 確保加載中間件的順序正確,加載完應(yīng)用路由后再加載 errorHandler。

Express 4 應(yīng)用

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();

// 環(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),否則不必加載它,可使用如下方式啟動應(yīng)用:

app.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

運行應(yīng)用

遷移完成后,應(yīng)用就變成了 Express 4 應(yīng)用。為了確保遷移成功,使用如下命令啟動應(yīng)用:

$ node .

輸入 http://localhost:3000,即可看到經(jīng)由 Express 4 渲染的主頁。

遷移到 Express 4 應(yīng)用生成器

生成 Express 應(yīng)用的命令行還是 express,為了升級到最新版本,您必須首先卸載 Express 3 的應(yīng)用生成器,然后安裝新的 express-generator。

安裝

如果您已經(jīng)安裝了 Express 3 應(yī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 命令就升級為 Express 4 應(yīng)用生成器了。

應(yīng)用生成器的變化

大部分命令參數(shù)和使用方法都維持不變,除過如下選項:

  • 刪掉了 --sessions 選項。
  • 刪掉了 --jshtml 選項。
  • 增加了 --hogan 選項以支持 Hogan.js。

示例

運行下述命令創(chuàng)建一個 Express 4 應(yīng)用:

$ express app4

如果查看 app4/app.js 的內(nèi)容,會發(fā)現(xiàn)應(yīng)用需要的所有中間件(不包括 express.static)都作為獨立模塊載入,而且再不顯式地加載 router 中間件。

您可能還會發(fā)現(xiàn),和舊的生成器生成的應(yīng)用相比, app.js 現(xiàn)在成了一個 Node 模塊。

安裝完依賴后,使用如下命令啟動應(yīng)用:

$ npm start

如果看一看 package.json 文件中的 npm 啟動腳本,會發(fā)現(xiàn)啟動應(yīng)用的真正命令是 node ./bin/www,在 Express 3 中則為 node app.js。

Express 4 應(yīng)用生成器生成的 app.js 是一個 Node 模塊,不能作為應(yīng)用(除非修改代碼)單獨啟動,需要通過一個 Node 文件加載并啟動,這里這個文件就是 node ./bin/www。

創(chuàng)建或啟動 Express 應(yīng)用時,bin 目錄或者文件名沒有后綴的 www 文件都不是必需的,它們只是生成器推薦的做法,請根據(jù)需要修改。

如果不想保留 www,想讓應(yīng)用變成 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 中了。我們并不推薦這樣做,這個練習(xí)只是為了幫助大家理解 ./bin/www 是如何工作的,以及為什么 app.js 不能再自己啟動。