Safe/performant 使 nginx 重定向 /?p=123 样式链接的方法
Safe/performant way to make nginx redirect /?p=123 style links
我正在尝试将 nginx 301 重定向 wordpress 风格 foo.com/?p=123
风格的链接指向固定的 URL。
从 If is evil 和其他文档中,我了解到危险的 if
语句是基于参数重定向的唯一方法,我发现这样的配置似乎可以完成工作:
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location = / {
root /usr/share/nginx/html;
index index.html index.htm;
if ($arg_p = 4) { return 301 /2012/12/hello-world; }
if ($arg_p = 15) { return 301 /about; }
# ... a few hundred more lines like this
}
但是,我猜想使用这种配置 nginx 将不得不通过所有这些 if
语句来解决顶级 foo.com/
请求,这可能并不理想。
什么是 "right" 硬编码像这样的大重定向列表,同时最小化 if
语句的 danger/cost 的方法?
第一个好主意是将重定向规则放在一个单独的文件中。这将使主要配置更具可读性。然后可以将包含规则的文件包含在 include 指令中。
另一个好主意是使用 map 而不是 if
,因为它有更简洁的语法来定义长列表。
假设您决定将规则放入 /path/to/redirect/rules.conf
。该文件的内容将如下所示:
# Each map defines the set of rules for one set of conditions.
# The blocks must be sorted in order of priority: every next
# map block has a higher priority than the previous one.
map $arg_p $p_condition {
default "";
4 /2012/12/hello-world;
15 /about;
# You can use regular expressions
~^1[6-9]$ /some/page;
}
# By combining the condition variables you can implement
# some sort of and/or/not logic in your rules
map "${arg_p}#${arg_q}" $pq_condition {
# Note that it is necessary to inherit the result
# of the previous map block to preserve them. And this
# is where the priority of the blocks comes from
default $p_condition;
# The values of p _and_ q are 4 and 15
4#15 /2012/12/hello-world;
# The value of p is 5 _or_ the value of q is 16
~"^5#.*" /another/page;
~"^.*?#16" /another/page;
# The value of p is _not_ 8 _and_ the value of q is 30
~"^[^8]#30" /the/very/special/page;
}
# The final block is of the highest priority. It defines
# the variable, which value will be used as the URL for redirection
map $args $url_to_redirect_to {
# Don't forget this important line
default $pq_condition;
# Here's another type of condition: check if the t variable
# is present in the list of GET paramters
~^(&|\?)t=.*$ /yet/another/page;
}
现在剩下要做的就是在主配置中使用定义的规则:
# Note that map directives must be placed out of the `server` block
include /path/to/redirect/rules.conf;
server {
...
location = / {
...
if ($url_to_redirect_to != "") {
rewrite ^ $url_to_redirect_to? permanent;
}
...
}
...
}
乍一看 map
块的级联可能看起来有些混乱,但是当您在其中放置大量规则时,您会发现这种方法的优势。
我正在尝试将 nginx 301 重定向 wordpress 风格 foo.com/?p=123
风格的链接指向固定的 URL。
从 If is evil 和其他文档中,我了解到危险的 if
语句是基于参数重定向的唯一方法,我发现这样的配置似乎可以完成工作:
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location = / {
root /usr/share/nginx/html;
index index.html index.htm;
if ($arg_p = 4) { return 301 /2012/12/hello-world; }
if ($arg_p = 15) { return 301 /about; }
# ... a few hundred more lines like this
}
但是,我猜想使用这种配置 nginx 将不得不通过所有这些 if
语句来解决顶级 foo.com/
请求,这可能并不理想。
什么是 "right" 硬编码像这样的大重定向列表,同时最小化 if
语句的 danger/cost 的方法?
第一个好主意是将重定向规则放在一个单独的文件中。这将使主要配置更具可读性。然后可以将包含规则的文件包含在 include 指令中。
另一个好主意是使用 map 而不是 if
,因为它有更简洁的语法来定义长列表。
假设您决定将规则放入 /path/to/redirect/rules.conf
。该文件的内容将如下所示:
# Each map defines the set of rules for one set of conditions.
# The blocks must be sorted in order of priority: every next
# map block has a higher priority than the previous one.
map $arg_p $p_condition {
default "";
4 /2012/12/hello-world;
15 /about;
# You can use regular expressions
~^1[6-9]$ /some/page;
}
# By combining the condition variables you can implement
# some sort of and/or/not logic in your rules
map "${arg_p}#${arg_q}" $pq_condition {
# Note that it is necessary to inherit the result
# of the previous map block to preserve them. And this
# is where the priority of the blocks comes from
default $p_condition;
# The values of p _and_ q are 4 and 15
4#15 /2012/12/hello-world;
# The value of p is 5 _or_ the value of q is 16
~"^5#.*" /another/page;
~"^.*?#16" /another/page;
# The value of p is _not_ 8 _and_ the value of q is 30
~"^[^8]#30" /the/very/special/page;
}
# The final block is of the highest priority. It defines
# the variable, which value will be used as the URL for redirection
map $args $url_to_redirect_to {
# Don't forget this important line
default $pq_condition;
# Here's another type of condition: check if the t variable
# is present in the list of GET paramters
~^(&|\?)t=.*$ /yet/another/page;
}
现在剩下要做的就是在主配置中使用定义的规则:
# Note that map directives must be placed out of the `server` block
include /path/to/redirect/rules.conf;
server {
...
location = / {
...
if ($url_to_redirect_to != "") {
rewrite ^ $url_to_redirect_to? permanent;
}
...
}
...
}
乍一看 map
块的级联可能看起来有些混乱,但是当您在其中放置大量规则时,您会发现这种方法的优势。