我正在查看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);
});
我意识到此功能的核心是pathRegexp()
中定义的名为lib/utils.js的方法。方法定义如下:
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
,它以这种方式对路径名的匹配部分进行分组:
斜线
/
符号
格式 我不知道这个的目的是什么,需要解释。
键
\w+
符号后面的单词(即:
)
捕获
在key
前写的正则表达式。应该用括号括起来(例如(.\\d+)
)
可选的
?
key
符号
星
*
符号
并且回调处理程序从上面的组构建一个正则表达式。
现在问题是,这里format
的目的是什么?
我的理解如下:
(format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)'))
和上面提到的正则表达式是,
如果在.
组之后加上slash
符号并且未指定匹配条件(正则表达式包裹在key
之后的括号中),则生成的正则表达式与其他符号匹配path
之前的.
或/
符号。
那有什么意义呢?
我问这个,因为:
答案 0 :(得分:5)
用于正确匹配文件扩展名。
给定路径'/path/:file.:ext'
,考虑表达式之间的差异:
// With 'format' checking
/^\/path\/(?:([^\/]+?))(?:\.([^\/\.]+?))\/?$/
// Without 'format' checking
/^\/path\/(?:([^\/]+?))(?:([^\/]+?))\/?$/
在第一种情况下,你最终得到了params
{
file: 'file',
ext: 'js'
}
但没有格式检查,你最终会得到这个:
{
file: 'f',
ext: 'ile.js'
}