如果path =“/”和查询变量“band”!=“”,我试图将$ qualifies变量设置为1。我已经能够找出下面的单独部分(我想),但想知道是否有更简单的方法。似乎这可能都在1张地图中:
map $request_uri $myvar {
~(?<captured_path>[^?]*) $captured_path;
}
map $arg_band $band{
"" 0;
default 1;
}
map "$myvar:$band" $qualifies{
default 0;
"/:1" 1;
}
想要这样做是因为丑陋而且知道可能有更好的方法。
似乎没有意识到$uri
中已经有一个无需查询的URL,因此,另一个可能的解决方案如下:
map $uri:$arg_band $qualified {
default 0;
~^/:[^:]+$ 1;
}
请注意,$uri
和$arg_band
都可以包含“怪异”字符(例如,两者都可以包含?
,in case of $uri
, through %3f
),因此,您必须确保在正则表达式中匹配您的实际分隔符,而不是用户提供的占位符。这可以通过使其随机,长且保密,或通过限制来自用户的可接受输入来完成。
请注意,在不知道使用了什么其他逻辑以及如何使用变量的情况下,大多数明显且美观的解决方案实际上都会包含潜在的安全漏洞并且不正确(例如,如果$arg_band
确实包含:
,则上述解决方案可能不正确)。
所以,你试图将$qualifies
设置为1
,如果$uri
都是/
并且$arg_band
没有设置为什么?
与你自己的代码相比较的基本思想是我们必须对逻辑和操作进行逆向逻辑或 - (a && b)
总是与!(!a || !b)
相同 - 一旦你知道了理论,那么剩下的只是一点点编码。
事实上,使用单个http://nginx.org/r/map非常简单:
map $request_uri $qualifies {
default 1;
~^[^?]+[?]band=[^&] 0; # match if $arg_band set to .+, case 1
~^[^?]+[?].*&band=[^&] 0; # match if $arg_band set to .+, case 2
~^[/]+[^/?]+ 0; # match if $uri is set to "/"
}
如果你不喜欢处理$arg_band
的双重案例,你可以使用pcre
的lookbehind运算符,但是,我相信上面两种情况实际上可能比下面的单一情况更有效和正确:
^[^?]+[?].*(?<=[?&])band=[^&] # incorrect! will match /??band=a
我个人的一个后续问题是上面的组合正则表达式是否真的正确,并且与nginx自己解析$arg_band
的方式相匹配。这可以通过对nginx.conf运行各种字符串来测试,它只是像return 200 $args\t$arg_band\t$uri\t$request_uri\n;
那样;我发现$uri
总是在第一个?
切割,而$args
本身可能包含第二个?
,而个别变量名称必须从请求的第一个?
开始,或者从第一个问号后的&
开始,例如,$args
中的问号被视为常规字符,因此,由于正则表达式与nginx中的实际$ arg_band之间的字符串(如(?<=[?&])
)的匹配不同,上面的后视代码w / /??band=t
不正确。
所以,如果你仍想要结合这两个表达式,那么以下应该是最正确的:
^[^?]+[?](?:.*&)?band=[^&]
制定整体解决方案:
map $request_uri $qualifies {
default 1;
~^[^?]+[?](.*&)?band=[^&] 0;
~^[/]+[^/?]+ 0;
}
但是,你还必须考虑你的解决方案必须绝对正确,如果需要非常高的正确性,那么你可能不适合自己解析$request_uri
(就像一个例子,当$request_uri
是/a/../
,由于URL规范化,$uri
将只是/
,并且您的原始解决方案已经受此影响)。