• 欢迎访问新概念博客,研究javascript,css3,html5,nodejs,Ext js等技术研究,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入新概念博客

Nginx配置中的if判断

系统运维 新概念 2年前 (2021-12-23) 6219次浏览 0个评论 扫描二维码

当 rewrite 的重写规则满足不了需求时,比如需要判断当文件不存在时、当路径包含 xx 时等条件,则需要用到 if

if 语法、

if (表达式) {

}

表达式语法:

  1. 当表达式只是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false
  2. 直接比较变量和内容时,使用=或!=
  3. -f 和!-f 用来判断是否存在文件
  4. -d 和!-d 用来判断是否存在目录
  5. -e 和!-e 用来判断是否存在文件或目录
  6. -x 和!-x 用来判断文件是否可执行

为了配置 if 的条件判断,这里需要用到 nginx 中内置的全局变量

$args 这个变量等于请求行中的参数,同$query_string
$content_length 请求头中的 Content-length 字段。
$content_type 请求头中的 Content-Type 字段。
$document_root 当前请求在 root 指令中指定的值。
$host 请求主机头字段,否则为服务器名称。
$http_user_agent 客户端 agent 信息
$http_cookie 客户端 cookie 信息
$limit_rate 这个变量可以限制连接速率。
$request_method 客户端请求的动作,通常为 GET 或 POST。
$remote_addr 客户端的 IP 地址。
$remote_port 客户端的端口。
$remote_user 已经经过 Auth Basic Module 验证的用户名。
$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 相同。

 

举例说明

1、如果文件不存在则返回 400

if (!-f $request_filename) {
return 400;
}

 

2、如果 host 不是 jouypub.com,则 301 到 jouypub.com 中

if ( $host != 'jouypub.com' ){
rewrite ^/(.*)$ https://jouypub.com/$1 permanent;
}

 

3、如果请求类型不是 POST 则返回 405

if ($request_method = POST) {
return 405;
}

 

4、如果参数中有a=1则 301 到指定域名

if ($args ~ a=1) {
rewrite ^ http://example.com/ permanent;
}

 

5、在某种场景下可结合 location 规则来使用,如:

# 访问 /test.html 时
location = /test.html {
# 设置默认值为 xiaowu
set $name xiaowu;
# 如果参数中有 name=xx 则使用该值
if ($args ~* name=(\w+?)(&|$)) {
set $name $1;
}
# 301
rewrite ^ /$name.html permanent;
}

 

上面表示:
/test.html => /xiaowu.html
/test.html?name=ok => /ok.html?name=ok

 

Nginx 中 if 语句里的 AND,OR 多重判断

最近遇到 Nginx 钟多条件判断,网上查了查资料,这里记录一下。

一、if 语句中的判断条件(nginx)
1、正则表达式匹配:
==:等值比较;

~:与指定正则表达式模式匹配时返回“真”,判断匹配与否时区分字符大小写;

~*:与指定正则表达式模式匹配时返回“真”,判断匹配与否时不区分字符大小写;

!~:与指定正则表达式模式不匹配时返回“真”,判断匹配与否时区分字符大小写;

!~*:与指定正则表达式模式不匹配时返回“真”,判断匹配与否时不区分字符大小写;

2、文件及目录匹配判断:
-f, !-f:判断指定的路径是否为存在且为文件;

-d, !-d:判断指定的路径是否为存在且为目录;

-e, !-e:判断指定的路径是否存在,文件或目录均可;

-x, !-x:判断指定路径的文件是否存在且可执行;

二、场景:
有些公司可能有这样的需求,如:我的网站或者网页游戏需要更新,所有的用户或者玩家访问到的是一个停服更新页面,而本公司的 IP 可以访问,甚至说本公司的某个内网 IP 可以访问,用于确认更新成功与否,针对这个问题写了如下的访问控制规则:

Nginx 多重条件判断(只是一个简单的例子,自己可以更改或者增加更多的判断条件),下面是两个例子和写法:1、可以作为 nginx 的停服更新使用,仅允许 222.222.222.222 或者内网的两个 IP 访问,其他 IP 都 rewrite 到停服页面
Nginx.conf 中加入在你项目的正确位置

set $my_ip '';

#注意这里的$remote_addr 如何用了负载均衡的话,这里应该是$http_x_forwarded_for
if ( $remote_addr = 222.222.222.222) {
set $my_ip 1;
}
if ( $remote_addr = 192.168.1.170 ) {
set $my_ip 1;
}
if ( $remote_addr = 192.168.1.169 ) {
set $my_ip 1;
}

#将*.php 转到 tingfu.html

if ( $my_ip != 1) {
rewrite ^/design/(.*)\.php$ /tingfu.html?$1&;
}

 

2、访问某个 php 应用的时候我只想让内部的某个 IP 访问,其他的 IP 都转到另一个 PHP 上。如下:
访问 test.php,且 IP 不等 222.222.222.222 的跳转到 55555.php:

set $test '';
if ( $request_uri ~* /img/test.php ) {
set $test P;
}

if ( $http_x_forwarded_for !~* ^222\.222\.222\.222.* ) {
set $test "${test}C";
}

if ( $test = PC ) { #当条件符合 访问 test.php 并且 ip 不是 222.222.222.222 的 转发到 55555.php
rewrite ^(.*)$ /img/55555.php permanent;
}

 

例子 1
原理 就是用 SET 变量进行。

AND 就用变量叠加,OR 就用 0 或 1 切换。

nginx 的配置中不支持 if 条件的逻辑与/逻辑或运算 ,并且不支持 if 的嵌套语法,我们可以用变量的方式来实现:

首先是伪代码(即不被 nginx 支持),写在这里只是为了方便理解:

if ($remote_addr ~ "^(12.34|56.78)" && $http_user_agent ~* "spider") {
return 403;
}
这是等效的,并真实可用的配置

set $flag 0;
if ($remote_addr ~ "^(12.34|56.78)") {
set $flag "${flag}1";
}
if ($http_user_agent ~* "spider") {
set $flag "${flag}2";
}
if ($flag = "012") {
return 403;
}

~~~~

 

nginx 的配置中不支持 if 条件的逻辑与/逻辑或运算 ,并且不支持 if 的嵌套语法,我们可以用变量的方式来实现

set $flag 0;
if ($host != 'www.imfeng.com') {
set $flag "${flag}1";
}
if ($http_user_agent != 'spider') {
set $flag "${flag}2";
}
if ($flag = "012") {
rewrite ^/(.*)$ http://www.imfeng.com/$1 permanent;
}

例子 2
location /log {
if ($http_user_agent ~ MSIE ) {
access_log /var/log/msie.log;
}
if ($http_user_agent ~ Opera ) {
access_log /var/log/opera.log;
}
if ($http_user_agent ~ Webkit ) {
access_log /var/log/webkit.log;
}
if ($http_user_agent ~ Mozilla ) {
access_log /var/log/mozilla.log;
}
add_header "Content-Type" "text/plain;charset=UTF-8";
return 200 "$http_user_agent";
}

新概念博客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Nginx配置中的if判断
喜欢 (3)
[新概念]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址