我正在查看express.js源代码,以了解它如何将命名路由参数映射到req.params
属性。
对于那些不知道的人来说,在express.js中,你可以定义带有命名参数的路由,使它们成为可选的,只允许具有特定格式的路由(以及更多):
app.get("/user/:id/:name?/:age(\d+)", function (req, res) {
console.log("ID is", req.params.id);
console.log("Name is", req.params.name || "not specified!");
console.log("Age is", req.params.age);
});
我意识到这个功能的核心是一个在lib/utils.js中定义的名为pathRegexp()
的方法。方法定义如下:
function pathRegexp(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(//(/g, '(?:/')
.replace(/(/)?(.)?:(w+)(?:((.*?)))?(?)?(*)?/g, function (_, slash, format, key, capture, optional, star) {
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '')
+ (star ? '(/*)?' : '');
})
.replace(/([/.])/g, '\$1')
.replace(/*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
重要的部分是第7行/(/)?(.)?:(w+)(?:((.*?)))?(?)?(*)?/g
中的正则表达式,它将pathname的匹配部分分组如下:
slash ,,, /
symbol ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, n,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
format ,
key ,,,,, 字(即。w+
)后:
symbol ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
一个写在key
前面的正则表达式。应该用圆括号括起来(例如:(.\d+)
)
key
后面的?
符号,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, n,,,,,,,,,
star ,,,,, *
symbol ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, n,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
和回调处理程序从上面的组构建一个正则表达式。
现在的问题是, format
在这里的目的是什么?
我的理解根据以下行:
(format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)'))
和上面提到的正则表达式是,
如果将.
符号放在slash
组之后,并且不指定匹配条件(在key
之后用括号括起来的正则表达式),则生成的正则表达式将匹配path
的其余部分,直到它到达.
或/
符号。
那有什么意义呢?
我问这个是因为:
- 我想在我的应用程序中提取和使用这个方法,并希望在使用它之前充分了解它是如何工作的。
- 我没有在express.js文档中找到关于它的任何内容。
- 我只是好奇:)
用于匹配文件扩展名等。
给定路径'/path/:file.:ext'
,考虑表达式之间的差异:
// With 'format' checking
/^/path/(?:([^/]+?))(?:.([^/.]+?))/?$/
// Without 'format' checking
/^/path/(?:([^/]+?))(?:([^/]+?))/?$/
在第一种情况下,最终得到的参数为
{
file: 'file',
ext: 'js'
}
但是没有格式检查,你会得到这样的结果:
{
file: 'f',
ext: 'ile.js'
}