路由
路由用于确定应用程序如何响应对特定端点的客户机请求,包含一个 URI(或路径)和一个特定的 HTTP 请求方法(GET、POST 等)。
每个路由可以具有一个或多个处理程序函数,这些函数在路由匹配时执行。
路由的基本结构:
app.METHOD(PATH,HANDLER)
其中:
-
app是express的实例。 -
METHOD是 HTTP 请求方法。 -
PATH是服务器上的路径。 -
HANDLER是在路由匹配时执行的函数。
一个最简单的路由示例:
const express = require('express')
const app = express()
//当对主页发出 GET 请求时,响应“hello world”
app.get('/', (req, res) => {
res.send('hello word')
})
路由方法
不同的类型的HTTP请求需要用对应的路由方法来响应,下面两个路由方法分别响应GET和POST请求:
//响应GET请求
app.get('/', (req, res) => {
res.send('get请求会触发')
})
//响应POST请求
app.post('/', (req, res) => {
res.send('post请求会触发')
})
Express支持以下派生自HTTP的路由方法:
checkout | mkcol | purge |
copy | move | put |
delete | m-search | report |
get | notify | search |
head | options | subscribe |
lock | patch | trace |
merge | post | unlock |
mkactivity | unsubscribe |
有一个特殊的路由方法app.all(),只要对对应路径(下面例子是/index)的请求都会执行处理程序,无论使用的是GET、POST、DELETE、PUT还是其他请求方法:
app.all('/index', (res, req) => {
console.log('执行了all的处理程序');
next() //将控制权传递给下一个中间件函数
})
路由路径
路由路径可以是字符串、字符串模式或正则表达式。
以下是基于字符串的路由路径的一些示例。
此路由路径将请求与根路由 / 匹配。
app.get('/', function (req, res) {
res.send('root');
});
此路由路径将请求与 /about 匹配。
app.get('/about', function (req, res) {
res.send('about');
});
此路由路径将请求与 /random.text 匹配。
app.get('/random.text', function (req, res) {
res.send('random.text');
});
以下是基于字符串模式的路由路径的一些示例。
此路由路径将匹配 acd 和 abcd。
app.get('/ab?cd', function(req, res) {
res.send('ab?cd');
});
此路由路径将匹配 abcd、abbcd、abbbcd 等。
app.get('/ab+cd', function(req, res) {
res.send('ab+cd');
});
此路由路径将匹配 abcd、abxcd、abRABDOMcd、ab123cd 等。
app.get('/ab*cd', function(req, res) {
res.send('ab*cd');
});
此路由路径将匹配 /abe 和 /abcde。
app.get('/ab(cd)?e', function(req, res) {
res.send('ab(cd)?e');
});
基于正则表达式的路由路径的示例:
此路由路径将匹配名称中具有“a”的所有路由。
app.get(/a/, function(req, res) {
res.send('/a/');
});
此路由路径将匹配 butterfly 和 dragonfly,但是不匹配 butterflyman、dragonfly man 等。
app.get(/.*fly$/, function(req, res) {
res.send('/.*fly$/');
});
路由参数
路由参数设置在路由路径上,用于获取路由路径中指定位置的值,捕获的值填充在req.params对象中,路径中指定的路由参数的名称作为各自的键。
在路由路径中用“ :”指定路由参数:
//路由路径
// userId 和 bookId 被指定为路由参数
'/users/:userId/books/:bookId'
//请求url
'http://localhost:3000/users/34/books/8989'
app.get('/users/:userId/books/:bookId', function (req, res) {
res.send(req.params) //{ "userId": "34", "bookId": "8989" }
})
特殊情况:带有连字符(-) 和(.)的路径
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" }
要更好地控制可由路由参数匹配的确切字符串,可以在括号 ( () ) 中附加正则表达式:
Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}
路由处理程序
单个回调函数可以处理路由。例如:
app.get('/example/a', function (req, res) {
res.send('Hello from A!')
})
多个回调函数可以处理一个路由(确保指定 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!')
})
回调函数数组可以处理路由。例如:
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])
响应方法
下表中响应对象 (res) 上的方法可以向客户端发送响应,并终止请求-响应周期。如果未从路由处理程序调用这些方法,则客户端请求将保持挂起状态。
| 方法 | 描述 |
|---|---|
res.download() | 提示将要下载文件。 |
res.end() | 结束响应进程。 |
res.json() | 发送 JSON 响应。 |
res.jsonp() | 在 JSONP 的支持下发送 JSON 响应。 |
res.redirect() | 重定向请求。 |
res.render() | 呈现视图模板。 |
res.send() | 发送各种类型的响应。 |
res.sendFile() | 以八位元流形式发送文件。 |
res.sendStatus() | 设置响应状态码并以响应主体形式发送其字符串表示。 |
app.router()
可以使用app.router()为同一个路由路径创建可连接的路由处理程序,这样可以减少代码冗余,使路由更加模块化。
下面是使用 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')
})
express.Router
使用espress.Router类创建模块化、可装载的路由处理程序。
以下示例将路由器创建为模块,在其中装入中间件,定义一些路由,然后安装在主应用程序的路径中。
在应用程序目录中创建名为 birds.js 的路由器文件,其中包含以下内容:
const express = require('express');
const 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;
接着,在应用程序中装入路由器模块:
const birds = require('./birds');
...
app.use('/birds', birds);
此应用程序现在可处理针对 /birds 和 /birds/about 的请求,调用特定于此路由的 timeLog 中间件函数。