if 条件判断
当需要判断文件不存在时、对不同的客户端IP执行不同的响应或请求路径符合某些条件时执行不同的逻辑,此时会需要用到 if 指令。
if 能在 server 或 location 段中使用,它的语法为:
if (condition) {
# ...
}if 条件
其中 condition 条件语法可以包括如下:
文件及目录匹配
- 使用
=或者!=直接比较变量内容,注意不是== - 使用
-f和!-f判断文件是否存在 - 使用
-d和!-d判断目录是否存在 - 使用
-e和!-e判断文件或目录是否存在 - 使用
-x和!-x用来判断文件是否可执行
- 使用
正则匹配
~区分大小写匹配指定正则表达式,当匹配时返回"真"~*不区分大小写匹配指定正则表达式,当匹配时返回"真"!~区分大小写匹配指定正则表达式,当不匹配时候返回"真"!~*不区分大小写匹配指定正则表达式,当不匹配时候返回"真"
并且 if 指令不支持多条件、不支持嵌套且不支持 else。
break 指令
遇到 break 则跳出,后面的指令不在执行,比如:
if (!-f $reque_filename) {
set $id = 1; # 有效的指令
break;
limit_rate 10k; # 无效的指令
}return 指令
完成对请求的处理,直接向客户端返回响应状态码。比如:
# 格式如下:
return code [text];
# 示例1:直接返回状态码
return 403;
# 示例2:拒绝没有有效身份验证令牌的请求时
return 401 "Access denied because token is expired or invalid";# 格式如下:
return code URL;
# 示例:重定向
return 301 $scheme://www.example.com$request_uri;# 格式如下:
return URL;
# 示例:重定向
return $scheme://www.example.com$request_uri;参数解释如下:
| 参数 | 描述 |
|---|---|
| code | 返回给客户端的 HTTP 状态码 |
| URL | 返回给客户端的 URL 地址 |
| text | 返回给客户端的响应体内容,支持变量。 |
return 指令使用简单,适用于重定向满足条件的情况,重写的 URL 适用于匹配 server 或 location 块的每个请求,并且可以使用标准 NGINX 变量构建重写的 URL。
rewrite 指令
rewrite regex replacement [flag];rewrite 指令使用指定的正则表达式 regex 来匹配请求的 URI,如果匹配成功,则使用 replacement 更改URI,指令会根据配置文件中的顺序来执行。
同时可以使用 flag 标识来终止指令的进一步处理。
如果替换字符串 replacement 以 http://、https:// 或 $scheme 开头,则停止处理后续内容并直接重定向返回给客户端。
location / {
# 当匹配 正则表达式 /test/(.*)时 请求将被临时重定向到 http://www.$1.com
# 相当于 flag 写为 redirect
rewrite /test/(.*) http://www.$1.com;
return 200 "ok";
}
# 在浏览器中输入 127.0.0.1:8080/test1/baidu
# 则临时重定向到 http://www.baidu.com
# 后面的 return 指令将没有机会执行了location / {
rewrite /test/(.*) www.$1.com;
return 200 "ok";
}
# 发送请求如下
# curl 127.0.0.1:8080/test1/baidu
# ok
# 此处没有带 http:// 所以只是简单的重写。请求的 uri 由 /test1/baidu 重写为 www.baidu.com
# 因为会顺序执行 rewrite 指令,所以下一步执行 return 指令响应了 ok 字符串注意重写表达式只对相对路径有效。如果需要配对主机名,应该使用 if 语句,示例如下:
if ( $host ~* www\.(.*) ) {
set $host_without_www $1;
rewrite ^(.*)$ $scheme://$host_without_www$1 permanent;
}执行顺序
执行 server 块的 rewrite 指令
执行 location 匹配
执行选定的 location 中的 rewrite 指令
如果其中某步中的 URI 被重写,则重新循环执行 1 - 3,直到找到真实存在的文件,如果循环超过10次,则返回 500 Internal Server Error 错误。
flag 标识
last: 相当于Apache的[L]标记,表示完成rewritebreak: 停止执行当前虚拟主机的后续rewrite指令集redirect: 返回302临时重定向,地址栏会显示跳转后的地址permanent: 返回301永久重定向,地址栏会显示跳转后的地址
last和break的区别
last一般写在 server 代码段和 if 条件判断中,而break一般使用在 location 中;last不终止重写后的 url 匹配,即新的 url 会再从 server 走一遍匹配流程,而break终止重写后的匹配;break和last都能组织继续执行后面的rewrite指令;
set 指令
设置变量,语法如下:
set $variable value;Nginx 支持的 http 变量实现在 ngx_http_variables.c 的 ngx_http_core_variables 存储实现。
| 变量名 | 简单说明 |
|---|---|
$arg_PARAMETER | 这个变量包含GET请求中,如果有变量 PARAMETER 时的值 |
$args | 这个变量等于请求行中的参数,同 $query_string |
$binary_remote_addr | 二进制的客户地址 |
$body_bytes_sent | 响应时送出的body字节数数量。即使连接中断,这个数据也是精确的 |
$content_length | 请求头中的 Content-length 字段。 |
$content_type | 请求头中的 Content-Type 字段。 |
$cookie_COOKIE | cookie COOKIE变量的值 |
$document_root | 当前请求在 root 指令中指定的值。 |
$host | 请求主机头字段,否则为服务器名称。 |
$http_user_agent | 客户端 agent 信息 |
$http_cookie | 客户端 cookie 信息 |
$limit_rate | 这个变量可以限制连接速率。 |
$request_body_file | 客户端请求主体信息的临时文件名 |
$request_method | 客户端请求的动作,通常为 GET 或 POST 。 |
$remote_addr | 客户端的 IP 地址,如果上层使用了负载均衡可以尝试获取 $http_x_forwarded_for 的值 |
$remote_port | 客户端的端口。 |
$remote_user | 已经经过Auth Basic Module验证的用户名。 |
$request_completion | 如果请求结束,设置为OK。当请求未结束或如果该请求不是请求链串的最后一个时为空 |
$request_filename | 当前请求的文件路径,由 root 或 alias 指令与URI请求生成。 |
$scheme | HTTP方法(如http,https)。 |
$server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$request_uri | 包含请求参数的原始URI,不包含主机名,如:/foo/bar.php?arg=baz。 |
$uri | 不带请求参数的当前URI,$uri不包含主机名,如 /foo/bar.html。 |
$document_uri | 与 $uri 相同。 |
可以通过查看nginx 中内置的全局变量文档获得更多详情。
举例
如果文件不存在返回 400
if (!-f $request_filename) {
return 400;
}当访问的文件和目录不存在时,重定向到某个php文件
if( !-e $request_filename ) {
rewrite ^/(.*)$ index.php last;
}如果主机不是 example.com 则跳转到 example.com
if ($host != example.com) {
rewrite ^/(.*)$ https://example.com/$1 permanent;
}如果请求类型不是 POST 则返回 405
if ($request_method = POST) {
return 405;
}如果请求参数中有 a=1 则 301 到其他域名
if ($args ~ a=1) {
rewrite ^ http://example.com/ permanent;
}禁止访问以.sh,.flv,.mp3为后缀名的文件
location ~ .*\.(sh|flv|mp3)$ {
return 403;
}禁止访问多个目录
禁止访问 cron 和 templates 开头的目录。
location ~ ^/(cron|templates)/ {
deny all;
break;
}Nginx 多重条件判断
nginx 的配置中不支持 if 条件的逻辑与/逻辑或运算 ,并且不支持 if 的嵌套语法。
or或者当站点或页面还没有上线,需要仅允许指定 IP 访问整站或特定URI,其他 IP 都返回 405 状态码。
针对上面的需求,Nginx 可以使用正则表达式,或者使用 set 指定定义变量。
比如访问者的 IP 是
8.8.8.8或者114.114.114.114时允许访问,其他 IP 访问则返回 405。nginxif ($remote_ip !~ "^(114|8)\.(114|8)\.(114|8)\.(114|8)$") { return 405; }nginxset $allow_ip 0; if ($remote_addr = 114.114.114.114) { set $allow_ip 1; } if ($remote_addr = 8.8.8.8) { set $allow_ip 1; } if ($allow_ip != 1) { return 405; }以上是或者的关系,也就是多个条件中满足其一即可。
and并且nginxset $and 1; if (<not condition>) { set $and 0; } if (<not condition>) { set $and 0; } if ($and) { # ... }nginxset $and "" if (<condition>) { set $and "0"; } if (<condition>) { set $and "${and}1"; } if ($and = "01") { # ... }