相比与 Apache,Nginx 的 config 写起来更舒服一些。
但是,很多情况下,我们的需求可能会稍稍有些复杂,例如在一个判断语句中使用多个条件。Apache 写这种判断很简单,但使用 Nginx 该如何实现呢?
Nginx 中的 if/else 的语法与大多数语言一致:
if (<condition>) {
# Do something
} else {
# Do something
}
虽然 Nginx 并非编程语言,我们还是先来试试在其它语言中常用的手段吧。
试错
使用逻辑运算符
if (<condition1> AND <condition2>) {
# Do something
}
用 nginx -t
测试一下,报错...
试试用符号?
if (<condition1> && <condition2>) {
# Do something
}
还是有问题,看来 Nginx 并不支持逻辑运算符。
使用多个 if 块嵌套
试试“曲线救国”:
if (<condition1>) {
if (<condition2>) {
# Do something
}
}
nginx -t
,还是报错...
正确的姿势
在网上找了一些文章,终于解决了这个问题。
关键就在于:用变量存储状态。
“或”
set $foo 0;
if (<condition1>) {
set $foo 1;
}
if (<condition2>) {
set $foo 1;
}
if ($foo = 1) {
# Do something
}
只要两个条件中有任意一个成立,$foo 就会被赋值为 1,最后一个代码块就会被执行。
另外,如果“或”用在判断的变量的值时,可以用 |
更简单地解决:
if ($letter ~ ("A"|"B"|"C"|"D")) {
# Do something
}
但需要注意的是,不能这样写:
if ($letter ~ ("A"|"B") | $letter ~ ("C"|"D")) {
# Do something else
}
“与”
set $foo "";
if (<condition1>) {
set "${foo}1";
}
if (<condition2>) {
set "${foo}1";
}
if ($foo ~* "11") {
# Do something
}
首先把 $foo 清空,之后每当有一个条件成立,就会在 $foo 的结尾添加一个 1,当 $foo 中的字符串为“11”时,最后的代码块会被执行。
更多个条件组合
set $foo "";
if (<condition1>) {
set $foo "1";
} else {
set $foo "0";
}
if (<condition2>) {
set $foo "${foo}1";
} else {
set $foo "${foo}0";
}
if ( $foo ~* "011" ) {
# Do something
}
开始时 $foo 是空字符串,每当一个判断成立时 $foo 的最后会被添加一个 1,不成立则添加 0,以此类推,最后一个 if 块中 $foo 要匹配的字符串就是你希望实现的判断。
Nginx 的变量字符匹配中,~*
代表匹配,!~*
代表不匹配(实际上都是正则)
说了这么多,这些能干什么?
举个例子,当我们直接用 Nginx 给 Google Analytics 发送数据时,一般需要考虑两个条件:
- 是否是爬虫
- 用户是否开启 DNT(Do Not Track)
这时多条件判断就派上用场了。
类似的使用环境有很多。