express基本配置
# 服务
# 中间件配置
# 静态文件
# 语法
为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static
内置中间件函数。
此函数特征如下:
express.static(root, [options])
例如,通过如下代码就可以将 public
目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:
app.use(express.static('public'))
现在,你就可以访问 public
目录中的所有文件了:
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
2
3
4
5
# 路径重命名
app.use('/static', express.static('public'))
现在,你就可以通过带有 /static
前缀地址来访问 public
目录中的文件了。
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
2
3
4
5
# 路径动态
const path = require('path')
app.use('/static', express.static(path.join(__dirname, 'public')))
2
欲了解更多关于 serve-static
函数及其参数的知识,请参考 serve-static (opens new window)。
# 错误处理
# throw Error
app.get('/', (req, res, next) => {
setTimeout(() => {
try {
throw new Error('BROKEN')
} catch (err) {
next(err)
}
}, 100)
})
2
3
4
5
6
7
8
9
# use使用
const bodyParser = require('body-parser')
const methodOverride = require('method-override')
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use(logErrors)
app.use(clientErrorHandler)
app.use(errorHandler)
2
3
4
5
6
7
8
9
10
11
12
# 中间处理
分开
function logErrors (err, req, res, next) {
console.error(err.stack)
next(err)
}
function clientErrorHandler (err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!' })
} else {
next(err)
}
}
function errorHandler (err, req, res, next) {
res.status(500)
res.render('error', { error: err })
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
统一
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
2
3
4
5
6
7
Callback 一起处理
app.get('/a_route_behind_paywall',
(req, res, next) => {
if (!req.user.hasPaid) {
// continue handling this request
next('route')
} else {
next()
}
}, (req, res, next) => {
PaidContent.find((err, doc) => {
if (err) return next(err)
res.json(doc)
})
})
2
3
4
5
6
7
8
9
10
11
12
13
14
# 路由
路由是指应用程序的终结点 (URI) 如何响应客户端请求。有关路由的简介,请参阅基本路由 (opens new window)。
您可以使用与 HTTP 方法对应的 Express 对象的方法定义路由;例如,处理 GET 请求和处理 POST 请求。有关完整列表,请参阅应用。方法 (opens new window)。您还可以使用 app.all() (opens new window) 来处理所有 HTTP 方法,并使用 app.use() (opens new window) 将中间件指定为回调函数(有关详细信息,请参阅使用中间件 (opens new window))。app``app.get()``app.post
这些路由方法指定在应用程序收到对指定路由(终结点)和 HTTP 方法的请求时调用的回调函数(有时称为“处理程序函数”)。换句话说,应用程序“侦听”与指定路由和方法匹配的请求,当它检测到匹配项时,它会调用指定的回调函数。
实际上,路由方法可以有多个回调函数作为参数。对于多个回调函数,重要的是作为参数提供给回调函数,然后在函数体内进行调用以将控制权移交给下一个回调。next``next()
下面的代码是一个非常基本的路由的示例。
var express = require('express')
var app = express()
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
res.send('hello world')
})
2
3
4
5
6
7
# 路由方法
路由方法派生自其中一个 HTTP 方法,并附加到该类的实例。express
下面的代码是为 GET 和 POST 方法定义的到应用根目录的路由的示例。
// GET method route
app.get('/', function (req, res) {
res.send('GET request to the homepage')
})
// POST method route
app.post('/', function (req, res) {
res.send('POST request to the homepage')
})
2
3
4
5
6
7
8
9
Express 支持与所有 HTTP 请求方法对应的方法:、、、等。有关完整列表,请参阅应用。方法 (opens new window)。get``post
有一种特殊的路由方法,用于在所有 HTTP 请求方法的路径上加载中间件函数。例如,无论使用 GET、POST、PUT、DELETE 还是 http 模块 (opens new window)中支持的任何其他 HTTP 请求方法,都会对路由“/secret”的请求执行以下处理程序。app.all()
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
2
3
4
# 路由路径【推荐】
路由路径与请求方法结合使用,定义了可以发出请求的终结点。路由路径可以是字符串、字符串模式或正则表达式。
字符 、 和 是其正则表达式对应项的子集。连字符 () 和点 () 按字面意思解释基于字符串的路径。?``+``*``()``-``.
如果需要在路径字符串中使用美元字符 (),请将其转义后括在 和 中。例如,位于 “” 处的请求的路径字符串将为 “”。$``([``])``/data/$book``/data/([\$])book
Express使用路径到正则表达式 (opens new window)来匹配路由路径;请参阅路径到正则表达式文档,了解定义路由路径的所有可能性。Express Route Tester (opens new window) 是用于测试基本 Express 路由的便捷工具,尽管它不支持模式匹配。
查询字符串不是路由路径的一部分。
下面是基于字符串的路由路径的一些示例。
此路由路径会将请求与根路由 匹配。/
app.get('/', function (req, res) {
res.send('root')
})
2
3
此路由路径会将请求与 匹配。/about
app.get('/about', function (req, res) {
res.send('about')
})
2
3
此路由路径会将请求与 匹配。/random.text
app.get('/random.text', function (req, res) {
res.send('random.text')
})
2
3
下面是基于字符串模式的路由路径的一些示例。
此路由路径将与 匹配。acd``abcd
app.get('/ab?cd', function (req, res) {
res.send('ab?cd')
})
2
3
此路由路径将匹配 、 、 等。abcd``abbcd``abbbcd
app.get('/ab+cd', function (req, res) {
res.send('ab+cd')
})
2
3
此路由路径将匹配 、 、 等。abcd``abxcd``abRANDOMcd``ab123cd
app.get('/ab*cd', function (req, res) {
res.send('ab*cd')
})
2
3
此路由路径将与 匹配。/abe``/abcde
app.get('/ab(cd)?e', function (req, res) {
res.send('ab(cd)?e')
})
2
3
基于正则表达式的路由路径示例:
此路由路径将匹配其中带有“a”的任何内容。
app.get(/a/, function (req, res) {
res.send('/a/')
})
2
3
此路由路径将匹配 和 ,但不匹配 、 ,依此类推。butterfly``dragonfly``butterflyman``dragonflyman
app.get(/.*fly$/, function (req, res) {
res.send('/.*fly$/')
})
2
3
# 路由参数
路由参数是名为 URL 段的段,用于捕获在 URL 中其位置指定的值。捕获的值将填充到对象中,并将路径中指定的路由参数的名称作为其各自的键。req.params
Route path: /users/:userId/books/:bookId
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }
2
3
要使用路由参数定义路由,只需在路由的路径中指定路由参数,如下所示。
app.get('/users/:userId/books/:bookId', function (req, res) {
res.send(req.params)
})
2
3
路由参数的名称必须由“单词字符”([A-Za-z0-9_])组成。
由于连字符 () 和点 () 是按字面意思解释的,因此它们可以与路由参数一起使用,以达到有用的目的。-``.
Route path: /flights/:from-:to
Request URL: http://localhost:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }
Route path: /plantae/:genus.:species
Request URL: http://localhost:3000/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }
2
3
4
5
6
若要更好地控制可由路由参数匹配的确切字符串,可以在括号 () 中附加正则表达式:()
Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}
2
3
由于正则表达式通常是文本字符串的一部分,因此请确保使用额外的反斜杠转义任何字符,例如 。\``\\d+
在 Express 4.x 中,正则表达式中的 *
字符不以通常的方式解释 (opens new window)。解决方法是使用 而不是 .这可能会在 Express 5 中修复。{0,}``*
# 路由处理程序
您可以提供多个行为类似于中间件 (opens new window)的回调函数来处理请求。唯一的例外是,这些回调可能会调用以绕过剩余的路由回调。您可以使用此机制对路由施加前提条件,然后在没有理由继续使用当前路由时将控制权传递给后续路由。next('route')
路由处理程序可以是函数、函数数组或两者的组合的形式,如以下示例所示。
单个回调函数可以处理路由。例如:
app.get('/example/a', function (req, res) {
res.send('Hello from A!')
})
2
3
多个回调函数可以处理一个路由(确保指定对象)。例如:next
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
2
3
4
5
6
回调函数数组可以处理路由。例如:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/example/c', [cb0, cb1, cb2])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
独立函数和函数数组的组合可以处理路由。例如:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
app.get('/example/d', [cb0, cb1], function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from D!')
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 响应方法
下表中响应对象 () 上的方法可以向客户端发送响应,并终止请求-响应周期。如果这些方法都不是从路由处理程序调用的,则客户端请求将保持挂起。res
方法 | 描述 |
---|---|
nothing.download() (opens new window) | 提示下载文件。 |
res.end() (opens new window) | 结束响应过程。 |
res.json() (opens new window) | 发送 JSON 响应。 |
res.jsonp() (opens new window) | 发送支持 JSONP 的 JSON 响应。 |
res.redirect() (opens new window) | 重定向请求。 |
res.render() (opens new window) | 渲染视图样板。 |
res.send() (opens new window) | 发送各种类型的响应。 |
res.sendFile() (opens new window) | 将文件作为八位字节流发送。 |
res.sendStatus() (opens new window) | 设置响应状态代码并将其字符串表示形式作为响应正文发送。 |
# app.route()
您可以使用 为路由路径创建可链接的路由处理程序。由于路径是在单个位置指定的,因此创建模块化路由很有帮助,减少冗余和拼写错误也很有用。有关路由的详细信息,请参阅:路由器() 文档 (opens new window)。app.route()
下面是使用 定义的链接路由处理程序的示例。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')
})
2
3
4
5
6
7
8
9
10
# express路由器
使用该类创建模块化、可装载的路由处理程序。实例是一个完整的中间件和路由系统;因此,它通常被称为“迷你应用程序”。express.Router``Router
以下示例将路由器创建为模块,在其中加载中间件函数,定义一些路由,并将路由器模块挂载到主应用中的路径上。
创建在应用程序目录中命名的路由器文件,其中包含以下内容:birds.js
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
然后,在应用程序中加载路由器模块:
var birds = require('./birds')
// ...
app.use('/birds', birds)
2
3
4
5
应用现在将能够处理对 和 的请求,以及调用特定于路由的中间件函数。/birds``/birds/about``timeLog
# 中间件
Express是一个路由和中间件Web框架,具有自己的最小功能:Express应用程序本质上是一系列中间件函数调用。
中间件函数是有权访问请求对象 (opens new window) ()、响应对象 (opens new window) () 和应用程序请求-响应周期中的下一个中间件函数的函数。下一个中间件函数通常由名为 的变量表示。req``res``next
中间件函数可以执行以下任务:
- 执行任何代码。
- 对请求和响应对象进行更改。
- 结束请求-响应周期。
- 调用堆栈中的下一个中间件函数。
如果当前中间件函数未结束请求-响应周期,则必须调用以将控制权传递给下一个中间件函数。否则,请求将保持挂起。next()
Express 应用程序可以使用以下类型的中间件:
- 应用级中间件 (opens new window)
- 路由器级中间件 (opens new window)
- 错误处理中间件 (opens new window)
- 内置中间件 (opens new window)
- 第三方中间件 (opens new window)
您可以使用可选的挂载路径加载应用程序级和路由器级中间件。您还可以将一系列中间件函数加载在一起,从而在挂载点创建中间件系统的子堆栈。
# 应用级中间件
使用 and 函数将应用程序级中间件绑定到应用对象 (opens new window)的实例,其中中间件函数以小写形式处理的请求(如 GET、PUT 或 POST)的 HTTP 方法。app.use()``app.METHOD()``METHOD
此示例显示了一个没有挂载路径的中间件函数。每次应用收到请求时都会执行该函数。
var express = require('express')
var app = express()
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
2
3
4
5
6
7
此示例显示挂载在路径上的中间件函数。对于路径上任何类型的 HTTP 请求,将执行该函数。/user/:id``/user/:id
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
2
3
4
此示例显示了路由及其处理函数(中间件系统)。该函数处理对路径的 GET 请求。/user/:id
app.get('/user/:id', function (req, res, next) {
res.send('USER')
})
2
3
下面是在挂载点加载一系列中间件函数的示例,并带有挂载路径。它说明了一个中间件子堆栈,该堆栈将任何类型的 HTTP 请求的请求信息输出到路径。/user/:id
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()
})
2
3
4
5
6
7
路由处理程序使您能够为一个路径定义多个路由。下面的示例为 GET 请求定义了两个路由到路径。第二个路由不会导致任何问题,但永远不会被调用,因为第一个路由结束请求-响应周期。/user/:id
此示例显示了一个中间件子堆栈,该子堆栈处理对路径的 GET 请求。/user/:id
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.send(req.params.id)
})
2
3
4
5
6
7
8
9
10
11
要从路由器中间件堆栈中跳过中间件的其余部分,请调用以将控制权传递给下一个路由。注意:仅适用于使用 或 函数加载的中间件函数。next('route')``next('route')``app.METHOD()``router.METHOD()
此示例显示了一个中间件子堆栈,该子堆栈处理对路径的 GET 请求。/user/:id
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')
})
2
3
4
5
6
7
8
9
10
11
12
13
14
中间件也可以在数组中声明,以实现可重用性。
此示例显示一个数组,其中包含一个中间件子堆栈,该子堆栈处理对路径的 GET 请求/user/:id
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')
})
2
3
4
5
6
7
8
9
10
11
12
13
14
# 路由器级中间件
路由器级中间件的工作方式与应用程序级中间件相同,只是它绑定到 的实例。express.Router()
var router = express.Router()
使用 和 函数加载路由器级中间件。router.use()``router.METHOD()
下面的示例代码通过使用路由器级中间件复制上面显示的应用程序级中间件的中间件系统:
var express = require('express')
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)
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
38
要跳过路由器中间件的其余部分,请调用以将控制权传回路由器实例。next('router')
此示例显示了一个中间件子堆栈,该子堆栈处理对路径的 GET 请求。/user/:id
var express = require('express')
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)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 错误处理中间件
错误处理中间件始终采用四个参数。您必须提供四个参数以将其标识为错误处理中间件函数。即使不需要使用该对象,也必须指定它来维护签名。否则,该对象将被解释为常规中间件,并且将无法处理错误。next``next
以与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数,特别是使用签名):(err, req, res, next)
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
2
3
4
有关错误处理中间件的详细信息,请参阅:错误处理 (opens new window)。
# 内置中间件
从版本 4.x 开始,Express 不再依赖于 Connect (opens new window)。以前包含在 Express 中的中间件功能现在位于单独的模块中。请参阅中间件函数列表 (opens new window)。
Express 具有以下内置中间件功能:
- express.static (opens new window) 提供静态资源,如 HTML 文件、图像等。
- express.json (opens new window) 使用 JSON 有效负载解析传入的请求。注意:适用于 Express 4.16.0+
- express.urlencoded (opens new window) 使用 URL 编码的有效负载解析传入的请求。注意:适用于 Express 4.16.0+
# 第三方中间件
使用第三方中间件向 Express 应用添加功能。
安装 Node.js 模块以获取所需功能,然后在应用程序级别或路由器级别将其加载到应用程序中。
以下示例说明了如何安装和加载 Cookie 解析中间件函数。cookie-parser
$ npm install cookie-parser
var express = require('express')
var app = express()
var cookieParser = require('cookie-parser')
// load the cookie-parsing middleware
app.use(cookieParser())
2
3
4
5
6
7
有关 Express 常用的第三方中间件函数的部分列表,请参阅:第三方中间件 (opens new window)。
# babel转换es6
# 方式一
# 方式二
# 方式三
# 参考链接
- https://www.expressjs.com.cn/