黑人的命也是命。
支持平等正义倡议.

迁移到 Express 4

概述

Express 4 是对 Express 3 的重大更改。这意味着如果在依赖项中更新 Express 版本,现有的 Express 3 应用程序将无法运行。

本文涵盖

Express 4 中的更改

Express 4 中有几个重大更改

另请参阅

对 Express 核心和中间件系统的更改

Express 4 不再依赖 Connect,并从其核心删除了所有内置中间件,除了express.static 函数。这意味着 Express 现在是一个独立的路由和中间件 Web 框架,Express 版本控制和发布不受中间件更新的影响。

如果没有内置中间件,您必须显式添加运行应用程序所需的所有中间件。只需按照以下步骤操作

  1. 安装模块:npm install --save <module-name>
  2. 在您的应用程序中,需要模块:require('module-name')
  3. 根据模块文档使用该模块:app.use( ... )

下表列出了 Express 3 中间件及其在 Express 4 中的对应项。

Express 3Express 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 中间件的完整列表

在大多数情况下,您可以简单地用 Express 4 中的对应项替换旧的版本 3 中间件。有关详细信息,请参阅 GitHub 中的模块文档。

app.use 接受参数

在版本 4 中,您可以使用一个可变参数来定义加载中间件函数的路径,然后从路由处理程序中读取该参数的值。例如

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

路由系统

应用程序现在隐式加载路由中间件,因此您不再需要担心中间件相对于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实例是一个完整的中间件和路由系统;因此,它通常被称为“迷你应用程序”。

以下示例创建了一个路由器作为模块,在其中加载中间件,定义一些路由,并将它挂载到主应用程序上的路径。

例如,在应用程序目录中创建一个名为 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_ENVapp.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.jspackage.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 进行以下更改

  1. 内置的 Express 中间件函数 express.faviconexpress.loggerexpress.methodOverrideexpress.sessionexpress.bodyParserexpress.errorHandler 不再在 express 对象上可用。您必须手动安装它们的替代方案并在应用程序中加载它们。

  2. 您不再需要加载 app.router 函数。它不是有效的 Express 4 应用程序对象,因此请删除 app.use(app.router); 代码。

  3. 确保以正确的顺序加载中间件函数 - 在加载应用程序路由之后加载 errorHandler

版本 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 生成器。

应用程序生成器的更改

命令选项和使用在很大程度上保持不变,但以下例外

示例

执行以下命令以创建 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

创建 Express 应用程序或启动应用程序时,bin 目录和无扩展名的 www 文件并非必需。它们只是生成器提供的建议,您可以根据需要随意修改它们。

要删除 www 目录并保持“Express 3 方式”,请删除 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 文件不再自行启动。