我发现写两条路线更清晰,而不是写一条路线来匹配任何除了某些静态字符串:一条路线匹配某些静态字符串,另一条路线匹配其他所有内容。
// route that matches forbidden static strings, optionally with a postfix slug
$router->get('/{forbidden}/{optional_path?}', function () {
return response('Not found', 404);
})->where([ 'forbidden' => '(?:string1|string2)', 'optional_path' => '.*' ]);
// route that matches anything else (order of definition matters, must be last)
// might also consider using Route::fallback(), but I prefer to leave that
// alone in case my future self changes this below and opens up a hole
$router->get('/{anything?}', function () {
return response('Found', 200);
})->where([ 'anything' => '.*' ]);
这会导致*:
-
domain => 找到 200 个
-
domain/ => 找到 200 个
-
domain/abc => 找到 200 个
-
domain/string1 => 404 未找到
-
domain/string1/ => 404 未找到
-
domain/string1/abc => 404 未找到
-
domain/string10 => 找到 200 个
-
domain/string10/ => 找到 200 个
-
domain/string10/abc => 找到 200 个
-
domain/string2 => 404 未找到
-
domain/string2/ => 404 未找到
-
domain/string2/abc => 404 未找到
-
domain/string20 => 找到 200 个
-
domain/string20/ => 找到 200 个
-
domain/string20/abc => 找到 200 个
我觉得这更清楚,因为我不必考虑排除项。相反,我可以考虑完全匹配我想要禁止的内容,然后让 Laravel 对其他所有内容做出反应(失败开放策略)。这可能不符合您的设计标准,但我相信它会产生更清晰的代码。
此外,代码的性能更高。 ?! 必须回溯,这在定义上比前向匹配更昂贵。
我手头没有 Laravel 环境,但我会冒险猜测您的尝试为什么没有奏效。 Laravel 使用 does not support lookarounds on slugs 的 Symfony 路由器。 IIRC,当检测到环视时,Symfony 将环视应用到整个 URL,而不是您将模式绑定到的 slug。这与开发人员对锚 (^, $) 和贪婪 (*) 元字符如何工作的想法相混淆。这可能会导致在尝试使其工作时体验不佳,因为开发人员在一个假设下运行,但底层库在另一个假设下运行。
* 完全公开,我是为 Lumen 写的,然后在心里把它转换成 Laravel 格式。可能存在一些翻译错误。这是原始流明:
$router->get('/{forbidden:(?:string1|string2)}[/{optional_path:.*}]', function () {
return response('Not found', 404);
});
$router->get('{anything:.*}', function () {
return response('Found', 200);
});