# 迁移到 Express 4
# 概述
Express 4 是 Express 3 的重大变化。这意味着如果您在其依赖项中更新 Express 版本,现有的 Express 3 应用程序将无法运行。
本文涵盖:
Express 4 的变化。
将 Express 3 应用程序迁移到 Express 4 的 一个例子。
升级到 Express 4 应用程序生成器。
# Express 4 的变化
Express 4有几个重大变化:
Express 核心和中间件系统的变化。 对 Connect 和内置中间件的依赖被移除,所以你必须自己添加中间件。
更改路由系统。
其他各种变化。
也可以看看:
4.x 中的新功能
从 3.x 迁移到 4.x。
# Express 核心和中间件系统的变化
Express 4 不再依赖 Connect,并从其核心中删除了所有内置中间件,除了 express.static
功能。这意味着 Express 现在是一个独立的路由和中间件 Web 框架,并且 Express 版本控制和发布不受中间件更新的影响。
如果没有内置中间件,您必须显式添加运行应用程序所需的所有中间件。只需按照以下步骤操作:
下表列出了 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 中间件的 完整列表
。
在大多数情况下,您可以简单地将旧版本 3 中间件替换为 Express 4 对应的中间件。有关详细信息,请参阅 GitHub 中的模块文档。
# app.use 接受参数
在版本 4 中,您可以使用可变参数来定义加载中间件函数的路径,然后从路由处理程序中读取参数的值。例如:
app.use('/book/:id', (req, res, next) => {
console.log('ID:', req.params.id)
next()
})
# 路由系统
应用程序现在隐式加载路由中间件,因此您不再需要担心中间件相对于 router
中间件的加载顺序。
您定义路由的方式没有改变,但路由系统有两个新功能可以帮助您组织路由:
- 一种新方法,
app.route()
,为路由路径创建可链接的路由处理程序。 - 一个新的类,
express.Router
,创建模块化可挂载的路由处理程序。
# app.route() 方法
新的 app.route()
方法使您能够为路由路径创建可链接的路由处理程序。因为路径是在单个位置指定的,所以创建模块化路由是有帮助的,因为这有助于减少冗余和拼写错误。有关路由的更多信息,请参阅 Router() 文档
。
这是使用 app.route()
函数定义的链式路由处理程序的示例。
app.route('/book')
.get((req, res) => {
res.send('Get a random book')
})
.post((req, res) => {
res.send('Add a book')
})
.put((req, res) => {
res.send('Update the book')
})
# express.Router 类
另一个有助于组织路由的特性是一个新类 express.Router
,您可以使用它来创建模块化的可安装路由处理程序。一个Router
实例是一个完整的中间件和路由系统;因此,它通常被称为 "mini-app"。
以下示例将路由创建为模块,在其中加载中间件,定义一些路由,并将其安装在主应用程序的路径上。
例如,在app目录下创建一个名为birds.js
的路由文件,内容如下:
var express = require('express')
var router = express.Router()
// middleware specific to this router
router.use((req, res, next) => {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', (req, res) => {
res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
res.send('About birds')
})
module.exports = router
然后,在应用程序中加载路由模块:
var birds = require('./birds')
// ...
app.use('/birds', birds)
该应用程序现在将能够处理对 /birds
和 /birds/about
路径的请求,并将调用特定于该路由的 timeLog
中间件。
# 其他变化
下表列出了 Express 4 中其他小的但重要的变化:
对象 | 描述 |
---|---|
Node.js | Express 4 需要 Node.js 0.10.x 或更高版本,并且已放弃对 Node.js 0.8.x 的支持。 |
http.createServer() | 不再需要 http 模块,除非您需要直接使用它(socket.io/SPDY/HTTPS)。该应用程序可以使用 app.listen() 功能启动。 |
app.configure() | app.configure() 功能已被删除。使用 process.env.NODE_ENV 或 app.get('env') 功能检测环境并相应地配置应用程序。 |
json spaces | Express 4 中默认禁用 json spaces 应用程序属性。 |
req.accepted() | 使用 req.accepts()、req.acceptsEncodings()、req.acceptsCharsets() 和 req.acceptsLanguages()。 |
res.location() | 不再解析相对 URL。 |
req.params | 以前是一个数组;现在是一个对象。 |
res.locals | 以前是一个函数;现在是一个对象。 |
res.headerSent | 更改为 res.headersSent。 |
app.route | 现在以 app.mountpath 的形式提供。 |
res.on('header') | 已移除。 |
res.charset | 已移除。 |
res.setHeader('Set-Cookie', val) | 功能现在仅限于设置基本 cookie 值。使用 res.cookie() 来增加功能。 |
# 应用迁移示例
这是将 Express 3 应用程序迁移到 Express 4 的示例。感兴趣的文件是 app.js
和 package.json
。
# 版本 3 应用程序
# app.js
考虑具有以下 app.js
文件的 Express v.3 应用程序:
var express = require('express')
var routes = require('./routes')
var user = require('./routes/user')
var http = require('http')
var path = require('path')
var app = express()
// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
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')))
// development only
if (app.get('env') === 'development') {
app.use(express.errorHandler())
}
app.get('/', routes.index)
app.get('/users', user.list)
http.createServer(app).listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'))
})
# package.json
随附的版本 3 package.json
文件可能如下所示:
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.12.0",
"pug": "*"
}
}
# 迁移过程
通过安装 Express 4 应用程序所需的中间件并使用以下命令将 Express 和 Pug 更新到各自的最新版本来开始迁移过程:
$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save
对 app.js
进行以下更改:
# 版本 4 应用程序
# 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",
"pug": "^2.0.0",
"method-override": "^2.1.2",
"morgan": "^1.2.2",
"multer": "^0.1.3",
"serve-favicon": "^2.0.1"
}
}
# app.js
然后,删除无效代码,加载所需的中间件,并根据需要进行其他更改。app.js
文件将如下所示:
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()
// all environments
app.set('port', process.env.PORT || 3000)
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'pug')
app.use(favicon(path.join(__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)
// error handling middleware should be loaded after the loading the routes
if (app.get('env') === 'development') {
app.use(errorHandler())
}
var server = http.createServer(app)
server.listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'))
})
除非您需要直接使用 http 模块(socket.io/SPDY/HTTPS),否则不需要加载它,应用程序可以简单地以这种方式启动:
app.listen(app.get('port'), () => { console.log('Express server listening on port ' + app.get('port')) })
# 运行应用程序
迁移过程已完成,该应用程序现在是 Express 4 应用程序。要确认,请使用以下命令启动应用程序:
$ node .
加载 http://localhost:3000
并查看 Express 4 正在呈现的主页。
# 升级到 Express 4 应用程序生成器
生成 Express 应用的命令行工具依然是 express
,但要升级到新版本,必须卸载 Express 3 应用生成器,然后安装新的 express-generator
。
# 安装
如果您的系统上已经安装了 Express 3 应用程序生成器,则必须将其卸载:
$ npm uninstall -g express
根据您的文件和目录权限的配置方式,您可能需要使用 sudo
运行此命令。
现在安装新的生成器:
$ npm install -g express-generator
根据您的文件和目录权限的配置方式,您可能需要使用 sudo
运行此命令。
现在您系统上的 express
命令已更新为 Express 4 生成器。
# 应用生成器的变化
命令选项和使用基本保持不变,但有以下例外:
- 删除了
--sessions
选项。 - 删除了
--jshtml
选项。 - 添加了
--hogan
选项以支持Hogan.js
。
# 示例
执行以下命令创建 Express 4 应用程序:
$ express app4
如果查看 app4/app.js
文件的内容,您会注意到应用程序所需的所有中间件函数(express.static
除外)都作为独立模块加载,并且 router
中间件不再显式加载到应用程序中。
您还会注意到 app.js
文件现在是一个 Node.js 模块,与旧生成器生成的独立应用程序不同。
安装依赖项后,使用以下命令启动应用程序:
$ npm start
如果你查看 package.json
文件中的 npm start 脚本,你会注意到启动应用程序的实际命令是 node ./bin/www
,以前在 Express 3 中是 node app.js
。
因为 Express 4 生成器生成的 app.js
文件现在是一个 Node.js 模块,所以它不能再作为应用程序独立启动(除非您修改代码)。该模块必须加载到 Node.js 文件中并通过 Node.js 文件启动。在这种情况下,Node.js 文件是 ./bin/www
。
bin
目录和无扩展名的 www
文件都不是创建 Express 应用程序或启动应用程序所必需的。它们只是生成器提出的建议,因此请随意修改它们以满足您的需求。
要摆脱 www
目录并保留 "Express 3 way",请删除 app.js
文件末尾的 module.exports = app;
行,然后将以下代码粘贴到其位置:
app.set('port', process.env.PORT || 3000)
var server = app.listen(app.get('port'), () => {
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"
。
您现在已将 ./bin/www
的功能移回 app.js
。不建议进行此更改,但该练习可帮助您了解 ./bin/www
文件的工作原理以及 app.js
文件不再自行启动的原因。