avatar

Express框架入门

翻译自官方Express文档

妈的看完才发现官方有中文文档,傻了我都

安装

假设您已经安装了Node.js,请创建一个目录来保存您的应用程序,并将其作为您的工作目录。

1
2
$ mkdir myapp
$ cd myapp

使用npm init命令为app生成package.json

1
$ npm init

该命令提示您输入许多内容,例如应用程序的名称和版本。现在,您只需点击RETURN即可接受其中大多数的默认设置,但以下情况除外:

1
entry point: (index.js)

输入app.js,或输入任何您想要的主文件名称。如果需要,请按index.jsRETURN接受建议的默认文件名。

现在,在myapp目录中安装Express 并将其保存在依赖项列表中。例如:

1
$ npm install express --save

要临时安装Express而不将其添加到依赖项列表中,请执行以下操作:

1
$ npm install express --no-save

默认情况下,版本为npm 5.0+ npm install将模块添加到文件dependencies列表中package.json。对于npm的早期版本,必须--save显式指定该选项。然后,npm install在app目录中运行后,将自动在依赖项列表中安装模块。

Hello World案例

本质上,下面嵌入是您可以创建的最简单的Express应用程序。它是一个单一文件的应用程序,而不是您使用Express生成器所能得到的

1
2
3
4
5
6
7
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

此应用程序启动服务器,并在端口3000上侦听连接。该应用会显示“ Hello World!”。用于根URL(/)或route请求。对于其他所有路径,它将以404 Not Found响应。

本地运行

首先创建一个名为的目录myapp,更改为目录并运行npm init。然后express按照安装指南的依赖关系进行安装

myapp目录中,创建一个名为的文件,app.js并复制上面示例中的代码。

req(要求)和res(响应)是完全一样的对象节点提供,这样你就可以调用 req.pipe()req.on('data', callback)和其他任何你会怎么做,没有任何明示参与。

使用以下命令运行该应用程序:

1
$ node app.js

然后,http://localhost:3000/在浏览器中加载以查看输出。

Express application generator

使用应用程序生成器工具express-generator来快速创建应用程序框架。

您可以使用以下npx命令运行应用程序生成器(在Node.js 8.2.0中可用)。

1
$ npx express-generator

对于早期的Node版本,将应用程序生成器作为全局npm软件包安装,然后启动它。

1
2
$ npm install -g express-generator
$ express

显示带有以下-h选项的命令选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ express -h

Usage: express [options] [dir]

Options:

-h, --help output usage information
--version output the version number
-e, --ejs add ejs engine support
--hbs add handlebars engine support
--pug add pug engine support
-H, --hogan add hogan.js engine support
--no-view generate without view engine
-v, --view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git add .gitignore
-f, --force force on non-empty directory

例如,以下创建了一个名为myapp的Express应用程序。该应用程序将在当前工作目录的名为myapp的文件夹中创建,并且视图引擎将设置为Pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ express --view=pug myapp

create : myapp
create : myapp/package.json
create : myapp/app.js
create : myapp/public
create : myapp/public/javascripts
create : myapp/public/images
create : myapp/routes
create : myapp/routes/index.js
create : myapp/routes/users.js
create : myapp/public/stylesheets
create : myapp/public/stylesheets/style.css
create : myapp/views
create : myapp/views/index.pug
create : myapp/views/layout.pug
create : myapp/views/error.pug
create : myapp/bin
create : myapp/bin/www

然后安装依赖项:

1
2
$ cd myapp
$ npm install

在MacOS或Linux上,使用以下命令运行应用程序:

1
$ DEBUG=myapp:* npm start

在Windows上,使用以下命令:

1
> set DEBUG=myapp:* & npm start

然后http://localhost:3000/在浏览器中加载以访问该应用程序。

生成的应用程序具有以下目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── app.js
├── bin
│ └── www
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.pug
├── index.pug
└── layout.pug

7 directories, 9 files

生成器创建的应用程序结构只是构建Express应用程序的多种方法之一。随意使用此结构或对其进行修改以最适合您的需求。

Basic routing

Routing是指确定应用程序如何响应客户端对特定端点的请求,该特定端点是URI(或路径)和特定的HTTP请求方法(GET,POST等)。

每个路由可以具有一个或多个处理程序函数,这些函数在路由匹配时执行。

路由定义采用以下结构:

1
app.METHOD(PATH, HANDLER)

其中

  • app是的实例express
  • METHOD是小写的HTTP请求方法
  • PATH 是服务器上的路径。
  • HANDLER 是当路由匹配时执行的函数。

本教程假定已创建expressnamed 实例,app并且服务器正在运行。如果您不熟悉创建和启动应用程序,请参阅Hello world示例

以下示例说明了定义简单的route。

Hello World!在首页上回应:

1
2
3
app.get('/', function (req, res) {
res.send('Hello World!')
})

在根route(/)(应用程序的主页)上响应POST请求:

1
2
3
app.post('/', function (req, res) {
res.send('Got a POST request')
})

响应对/userroute的PUT请求:

1
2
3
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user')
})

响应对/userroute的DELETE请求:

1
2
3
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user')
})

有关路由的更多详细信息,请参见routing指南

在Express中提供静态文件

要提供静态文件(例如图像,CSS文件和JavaScript文件),请使用express.staticExpress中的内置中间件功能。

function signature为:

1
express.static(root, [options])

root参数指定要从其提供静态资产的根目录。有关自options变量的更多信息,请参见express.static

例如,使用以下代码在名为的目录中提供图片,CSS文件和JavaScript文件public

1
app.use(express.static('public'))

现在,您可以加载public目录中的文件:

1
2
3
4
5
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

Express查找相对于静态目录的文件,因此静态目录的名称不是URL的一部分。

要使用多个静态资产目录,请多次调用express.static中间件函数:

1
2
app.use(express.static('public'))
app.use(express.static('files'))

Express使用express.static中间件功能按设置静态目录的顺序查找文件。

注意:为了获得最佳结果,请使用反向代理缓存来提高服务静态资产的性能。

要为该express.static函数所服务的文件创建虚拟路径前缀(文件系统中实际上不存在该路径),请为静态目录指定安装路径,如下所示:

1
app.use('/static', express.static('public'))

现在,您可以public/static路径前缀加载目录中的文件。

1
2
3
4
5
http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html

但是,您提供给express.static函数的路径是相对于您启动node过程的目录的。如果从另一个目录运行express app,则使用要提供服务的目录的绝对路径更为安全:

1
app.use('/static', express.static(path.join(__dirname, 'public')))

有关该serve-static函数及其选项的更多详细信息,请参见serve-static

使用中间件

Express是一个路由和中间件Web框架,其自身的功能很少:Express应用程序本质上是一系列中间件函数调用。

中间件功能是可以访问请求对象req),响应对象res)和应用程序的请求-响应周期中的下一个中间件功能的功能。下一个中间件功能通常由名为的变量表示next

中间件功能可以执行以下任务:

  • 执行任何代码。
  • 更改请求和响应对象。
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件函数。

如果当前的中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能。否则,该请求将被挂起。

Express应用程序可以使用以下类型的中间件:

您可以使用可选的安装路径加载应用程序级和路由器级中间件。您还可以将一系列中间件功能一起加载,这将在安装点创建中间件系统的子堆栈。

应用层中间件

使用和函数将应用程序级中间件绑定到应用程序对象的实例,靠app.use() and app.METHOD() functions, where METHOD is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase.

此示例显示了没有安装路径的中间件功能。每次应用收到请求时,都会执行该功能。

1
2
3
4
5
6
var app = express()

app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})

此示例显示了/user/:id路径上安装的中间件功能。该函数针对/user/:id路径上的任何类型的HTTP请求执行。

1
2
3
4
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method)
next()
})

此示例显示了router及其处理程序功能(中间件系统)。该函数处理对/user/:id路径的GET请求。

1
2
3
app.get('/user/:id', function (req, res, next) {
res.send('USER')
})

这是在具有安装路径的安装点加载一系列中间件功能的示例。它说明了中间件子堆栈,该中间件子堆栈将任何类型的HTTP请求的请求信息打印到/user/:id路径。

1
2
3
4
5
6
7
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})

route handler程序使您可以为一个路径定义多个路由。下面的示例为到/user/:id路径的GET请求定义了两条route。第二条路由不会引起任何问题,但是它将永远不会被调用,因为第一条路由会结束请求-响应周期。

此示例显示了一个中间件子堆栈,该子堆栈处理对/user/:id路径的GET请求。

1
2
3
4
5
6
7
8
9
10
11
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})

// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id)
})

要从路由器中间件堆栈中跳过其余中间件功能,请调用next('route')将控制权传递给下一条路由。 注意next('route')仅适用于使用app.METHOD()router.METHOD()函数加载的中间件函数。

此示例显示了一个中间件子堆栈,该子堆栈处理对/user/:id路径的GET请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// send a regular response
res.send('regular')
})

// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})

中间件也可以在数组中声明为可重用。

此示例显示了一个带有中间件子堆栈的数组,该子堆栈处理对/user/:id路径的GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function logOriginalUrl (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}

function logMethod (req, res, next) {
console.log('Request Type:', req.method)
next()
}

var logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, function (req, res, next) {
res.send('User Info')
})

路由器级中间件

路由器级中间件与应用程序级中间件的工作方式相同,只不过它绑定到的实例express.Router()

1
var router = express.Router()

使用router.use()router.METHOD()函数加载路由器级中间件。

以下示例代码通过使用路由器级中间件来复制上面显示的用于应用程序级中间件的中间件系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var app = express()
var router = express.Router()

// a middleware function with no mount path. This code is executed for every request to the router
router.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})

// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
router.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})

// a middleware sub-stack that handles GET requests to the /user/:id path
router.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next router
if (req.params.id === '0') next('route')
// otherwise pass control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// render a regular page
res.render('regular')
})

// handler for the /user/:id path, which renders a special page
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id)
res.render('special')
})

// mount the router on the app
app.use('/', router)

要跳过路由器的其余中间件功能,请调用next('router') 将控制权转回路由器实例。

此示例显示了一个中间件子堆栈,该子堆栈处理对/user/:id路径的GET请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var app = express()
var router = express.Router()

// predicate the router with a check and bail out when needed
router.use(function (req, res, next) {
if (!req.headers['x-auth']) return next('router')
next()
})

router.get('/user/:id', function (req, res) {
res.send('hello, user!')
})

// use the router and 401 anything falling through
app.use('/admin', router, function (req, res) {
res.sendStatus(401)
})

错误处理中间件

错误处理中间件始终采用四个参数。您必须提供四个参数以将其标识为错误处理中间件函数。即使不需要使用该next对象,也必须指定它以维护签名。否则,该next对象将被解释为常规中间件,并且将无法处理错误。

以与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数(特别是使用签名(err, req, res, next))之外:

1
2
3
4
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})

有关错误处理中间件的详细信息,请参见:错误处理

内置中间件

从版本4.x开始,Express不再依赖Connect。Express以前包含的中间件功能现在位于单独的模块中;请参阅中间件功能列表

Express具有以下内置的中间件功能:

  • express.static提供静态资产,例如HTML文件,图像等。
  • express.json使用JSON负载解析传入的请求。注意:Express 4.16.0+中可用
  • express.urlencoded使用URL编码的有效内容解析传入的请求。注意:Express 4.16.0+中可用

第三方中间件

使用第三方中间件向Express应用程序添加功能。

安装Node.js模块以获得所需的功能,然后在应用程序级别或路由器级别将其加载到您的应用程序中。

以下示例说明了如何安装和加载cookie解析中间件功能cookie-parser

1
2
3
4
5
6
7
$ npm install cookie-parser
var express = require('express')
var app = express()
var cookieParser = require('cookie-parser')

// load the cookie-parsing middleware
app.use(cookieParser())

有关Express常用的第三方中间件功能的部分列表,请参阅:第三方中间件

文章作者: 8128
文章链接: http://8128.me/2020/05/05/Express%E6%A1%86%E6%9E%B6%E5%85%A5%E9%97%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 8128's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论