¥Moving to Express 4
Express 4 是 Express 3 的重大变化。这意味着如果你在其依赖中更新 Express 版本,现有的 Express 3 应用将无法运行。
¥Express 4 is a breaking change from Express 3. That means an existing Express 3 app will not work if you update the Express version in its dependencies.
本文涵盖:
¥This article covers:
Express 4 有几个重大变化:
¥There are several significant changes in Express 4:
也可以看看:
¥See also:
Express 4 不再依赖 Connect,并从其核心中删除了所有内置中间件,除了 express.static
功能。这意味着 Express 现在是一个独立的路由和中间件 Web 框架,并且 Express 版本控制和发布不受中间件更新的影响。
¥Express 4 no longer depends on Connect, and removes all built-in
middleware from its core, except for the express.static
function. This means that
Express is now an independent routing and middleware web framework, and
Express versioning and releases are not affected by middleware updates.
如果没有内置中间件,你必须显式添加运行应用所需的所有中间件。只需按照以下步骤操作:
¥Without built-in middleware, you must explicitly add all the middleware that is required to run your app. Simply follow these steps:
安装模块:npm install --save <module-name>
¥Install the module: npm install --save <module-name>
在你的应用中,需要模块:require('module-name')
¥In your app, require the module: require('module-name')
根据其文档使用该模块:app.use( ... )
¥Use the module according to its documentation: app.use( ... )
下表列出了 Express 3 中间件及其在 Express 4 中的对应项。
¥The following table lists Express 3 middleware and their counterparts in 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 中间件的 完整列表。
¥Here is the complete list of Express 4 middleware.
在大多数情况下,你可以简单地将旧版本 3 中间件替换为 Express 4 对应的中间件。有关详细信息,请参阅 GitHub 中的模块文档。
¥In most cases, you can simply replace the old version 3 middleware with its Express 4 counterpart. For details, see the module documentation in GitHub.
app.use
accepts parameters在版本 4 中,你可以使用可变参数来定义加载中间件函数的路径,然后从路由处理程序中读取参数的值。例如:
¥In version 4 you can use a variable parameter to define the path where middleware functions are loaded, then read the value of the parameter from the route handler. For example:
app.use('/book/:id', (req, res, next) => {
console.log('ID:', req.params.id)
next()
})
应用现在隐式加载路由中间件,因此你不再需要担心中间件相对于 router
中间件的加载顺序。
¥Apps now implicitly load routing middleware, so you no longer have to
worry about the order in which middleware is loaded with respect to
the router
middleware.
你定义路由的方式没有改变,但路由系统有两个新功能可以帮助你组织路由:
¥The way you define routes is unchanged, but the routing system has two new features to help organize your routes:
一种新方法,app.route()
,为路由路径创建可链式的路由处理程序。
¥A new method, app.route()
, to create chainable route handlers for a route path.
一个新的类,express.Router
,创建模块化可挂载的路由处理程序。
¥A new class, express.Router
, to create modular mountable route handlers.
app.route()
method新的 app.route()
方法使你能够为路由路径创建可链式的路由处理程序。因为路径是在单个位置指定的,所以创建模块化路由是有帮助的,因为这有助于减少冗余和拼写错误。有关路由的更多信息,请参阅 Router()
文档。
¥The new app.route()
method enables you to create chainable route handlers
for a route path. Because the path is specified in a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more
information about routes, see Router()
documentation.
这是使用 app.route()
函数定义的链式路由处理程序的示例。
¥Here is an example of chained route handlers that are defined by using the app.route()
function.
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
class另一个有助于组织路由的特性是一个新类 express.Router
,你可以使用它来创建模块化的可挂载路由处理程序。一个 Router
实例就是一个完整的中间件和路由系统;因此,它通常被称为 “mini-app”。
¥The other feature that helps to organize routes is a new class,
express.Router
, that you can use to create modular mountable
route handlers. A Router
instance is a complete middleware and
routing system; for this reason it is often referred to as a “mini-app”.
以下示例将路由创建为模块,在其中加载中间件,定义一些路由,并将其安装在主应用的路径上。
¥The following example creates a router as a module, loads middleware in it, defines some routes, and mounts it on a path on the main app.
例如,在 app 目录下创建一个名为 birds.js
的路由文件,内容如下:
¥For example, create a router file named birds.js
in the app directory,
with the following content:
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
然后,在应用中加载路由模块:
¥Then, load the router module in the app:
var birds = require('./birds')
// ...
app.use('/birds', birds)
该应用现在将能够处理对 /birds
和 /birds/about
路径的请求,并将调用特定于该路由的 timeLog
中间件。
¥The app will now be able to handle requests to the /birds
and
/birds/about
paths, and will call the timeLog
middleware that is specific to the route.
下表列出了 Express 4 中其他小的但重要的变化:
¥The following table lists other small but important changes in Express 4:
目的 | 描述 |
---|---|
Node.js | Express 4 需要 Node.js 0.10.x 或更高版本,并已放弃对 Node.js 0.8.x 的支持。 |
|
不再需要 |
|
|
|
Express 4 中默认禁用 |
|
使用 |
|
不再解析相对 URL。 |
|
是一个数组;现在是一个对象。 |
|
是一个函数;现在是一个对象。 |
|
改为 |
|
现在可用作 |
|
已删除。 |
|
已删除。 |
|
功能现在仅限于设置基本 cookie 值。使用 |
这是将 Express 3 应用迁移到 Express 4 的示例。感兴趣的文件是 app.js
和 package.json
。
¥Here is an example of migrating an Express 3 application to Express 4.
The files of interest are app.js
and package.json
.
app.js
考虑具有以下 app.js
文件的 Express v.3 应用:
¥Consider an Express v.3 application with the following app.js
file:
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
文件可能如下所示:
¥The accompanying version 3 package.json
file might look
something like this:
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.12.0",
"pug": "*"
}
}
通过安装 Express 4 应用所需的中间件并使用以下命令将 Express 和 Pug 更新到各自的最新版本来开始迁移过程:
¥Begin the migration process by installing the required middleware for the Express 4 app and updating Express and Pug to their respective latest version with the following command:
$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save
对 app.js
进行以下更改:
¥Make the following changes to app.js
:
内置的 Express 中间件函数 express.favicon
、express.logger
、express.methodOverride
、express.session
、express.bodyParser
和 express.errorHandler
在 express
对象上不再可用。你必须手动安装它们的替代品并将它们加载到应用中。
¥The built-in Express middleware functions express.favicon
,
express.logger
, express.methodOverride
,
express.session
, express.bodyParser
and
express.errorHandler
are no longer available on the
express
object. You must install their alternatives
manually and load them in the app.
你不再需要加载 app.router
函数。它不是有效的 Express 4 应用对象,因此请删除 app.use(app.router);
代码。
¥You no longer need to load the app.router
function.
It is not a valid Express 4 app object, so remove the
app.use(app.router);
code.
确保中间件函数以正确的顺序加载 - 加载应用路由后加载 errorHandler
。
¥Make sure that the middleware functions are loaded in the correct order - load errorHandler
after loading the app routes.
package.json
运行上述 npm
命令将更新 package.json
,如下所示:
¥Running the above npm
command will update package.json
as follows:
{
"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
文件将如下所示:
¥Then, remove invalid code, load the required middleware, and make other
changes as necessary. The app.js
file will look like this:
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),否则不需要加载它,并且可以通过以下方式简单启动应用:
¥Unless you need to work directly with the http
module (socket.io/SPDY/HTTPS), loading it is not required, and the app can be simply started this way:
app.listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'))
})
迁移过程已完成,该应用现在是 Express 4 应用。要确认,请使用以下命令启动应用:
¥The migration process is complete, and the app is now an Express 4 app. To confirm, start the app by using the following command:
$ node .
加载 http://localhost:3000 并查看 Express 4 正在渲染的主页。
¥Load http://localhost:3000 and see the home page being rendered by Express 4.
生成 Express 应用的命令行工具依然是 express
,但要升级到新版本,必须卸载 Express 3 应用生成器,然后安装新的 express-generator
。
¥The command-line tool to generate an Express app is still
express
, but to upgrade to the new version, you must uninstall
the Express 3 app generator and then install the new
express-generator
.
如果你的系统上已经安装了 Express 3 应用生成器,则必须将其卸载:
¥If you already have the Express 3 app generator installed on your system, you must uninstall it:
$ npm uninstall -g express
根据你的文件和目录权限的配置方式,你可能需要使用 sudo
运行此命令。
¥Depending on how your file and directory privileges are configured,
you might need to run this command with sudo
.
现在安装新的生成器:
¥Now install the new generator:
$ npm install -g express-generator
根据你的文件和目录权限的配置方式,你可能需要使用 sudo
运行此命令。
¥Depending on how your file and directory privileges are configured,
you might need to run this command with sudo
.
现在你系统上的 express
命令已更新为 Express 4 生成器。
¥Now the express
command on your system is updated to the
Express 4 generator.
命令选项和使用基本保持不变,但有以下例外:
¥Command options and use largely remain the same, with the following exceptions:
删除了 --sessions
选项。
¥Removed the --sessions
option.
删除了 --jshtml
选项。
¥Removed the --jshtml
option.
添加了 --hogan
选项以支持 Hogan.js。
¥Added the --hogan
option to support Hogan.js.
执行以下命令创建 Express 4 应用:
¥Execute the following command to create an Express 4 app:
$ express app4
如果查看 app4/app.js
文件的内容,你会注意到应用所需的所有中间件函数(express.static
除外)都作为独立模块加载,并且 router
中间件不再显式加载到应用中。
¥If you look at the contents of the app4/app.js
file, you will notice
that all the middleware functions (except express.static
) that are required for
the app are loaded as independent modules, and the router
middleware
is no longer explicitly loaded in the app.
你还会注意到 app.js
文件现在是一个 Node.js 模块,与旧生成器生成的独立应用不同。
¥You will also notice that the app.js
file is now a Node.js module, in contrast to the standalone app that was generated by the old generator.
安装依赖后,使用以下命令启动应用:
¥After installing the dependencies, start the app by using the following command:
$ npm start
如果你查看 package.json
文件中的 npm start
脚本,你会注意到启动应用的实际命令是 node ./bin/www
,在 Express 3 中它曾经是 node app.js
。
¥If you look at the npm start
script in the package.json
file,
you will notice that the actual command that starts the app is
node ./bin/www
, which used to be node app.js
in Express 3.
因为 Express 4 生成器生成的 app.js
文件现在是一个 Node.js 模块,所以它不能再作为应用独立启动(除非你修改代码)。该模块必须加载到 Node.js 文件中并通过 Node.js 文件启动。在这种情况下,Node.js 文件是 ./bin/www
。
¥Because the app.js
file that was generated by the Express 4 generator
is now a Node.js module, it can no longer be started independently as an app
(unless you modify the code). The module must be loaded in a Node.js file
and started via the Node.js file. The Node.js file is ./bin/www
in this case.
bin
目录和无扩展名的 www
文件都不是创建 Express 应用或启动应用所必需的。它们只是生成器提出的建议,因此请随意修改它们以满足你的需求。
¥Neither the bin
directory nor the extensionless www
file is mandatory for creating an Express app or starting the app. They are
just suggestions made by the generator, so feel free to modify them to suit your
needs.
要删除 www
目录并保留 “Express 3 的方式” 目录,请删除 app.js
文件末尾的 module.exports = app;
行,然后将以下代码粘贴到其位置:
¥To get rid of the www
directory and keep things the “Express 3 way”,
delete the line that says module.exports = app;
at the end of the
app.js
file, then paste the following code in its place:
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
模块:
¥Ensure that you load the debug
module at the top of the app.js
file by using the following code:
var debug = require('debug')('app4')
接下来,将 package.json
文件中的 "start": "node ./bin/www"
更改为 "start": "node app.js"
。
¥Next, change "start": "node ./bin/www"
in the package.json
file to "start": "node app.js"
.
你现在已将 ./bin/www
的功能移回 app.js
。不建议进行此更改,但该练习可帮助你了解 ./bin/www
文件的工作原理以及 app.js
文件不再自行启动的原因。
¥You have now moved the functionality of ./bin/www
back to
app.js
. This change is not recommended, but the exercise helps you
to understand how the ./bin/www
file works, and why the app.js
file
no longer starts on its own.