先看问题

boss提了一个怪异的需求:每天上班时间8.30-18点可以访问某些url,其他时间段403。

如何解决

可以使用nginx的ngx_http_map_module模块结合ngx_http_access_module模块来实现

具体操作步骤如

1.在nginx中定义map,用来映射时间段,开关状态,url信息

#nginx $time_local 是一个nginx配置文件中的变量,它可以输出当前时间的本地时间戳,格式为:
#[dd/MM/yyyy:HH:mm:ss +0800],其中+0800表示当前时区为东八区

```
map $time_local $enable_feature {
  default off;
  "~^[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:0[8]:[3-5][0-9]:[0-5][0-9]" on;
  "~^[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:0[9]:[0-5][0-9]:[0-5][0-9]" on;
  "~^[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:1[0-7]:[0-5][0-9]:[0-5][0-9]" on;
}

map $request_uri $block {
	default 0;
  ~/servicegateway/test1/web1 1;
  ~/servicegateway/test2/web2 1;
}

map $block$enable_feature $forbid {
	default 0;
  lon 1;
}
```

2.在需要开关的配置项中使用if语句判断开关状态

if ($forbid = 0){
	return 403;
}

#注意:使用if语句和map模块可能会影响nginx性能,建议在高并发场景下使用其他方法实现

正则详解:
以下是匹配nginx日志中时间的正则表达式:
```
\d{1,2}/[a-zA-Z]{3}/\d{4}:\d{2}:\d{2}:\d{2}[+-]\d{4}
```
这个正则表达式可以匹配类似于以下格式的时间字符串:
```
01/Jan/2023:10:22:59 +0800
```

- `\d{2} | [0-9]{2}` 表示匹配两位数字
- `\w{3} | [a-zA-Z]{3}` 表示匹配三个字母
- `:` 和空格表示匹配一个冒号和空格
- `\s` 表示匹配一个空格
- `\+` 表示匹配一个加号
- `[+-]\d{4}` 表示匹配+或者-符号和四位数字

常用map定义

#根据访问的客户端访问不同的url
map $http_user_agent $mobile {
	default 0;
  ~*mobile|nokia|iphone|ipad|android|samsung|htc|blackberry 1;
}

其他配置(可自行尝试):

map $time_local $enable_feature {
        default 0;
        ~* "08:00-17:59" 1;
        ~* "00:00-07:59" 0;
    }

备注:

在 Nginx 中,$time 变量表示当前时间。它是一个内置变量,可以用于在配置文件中获取当前的日期和时间。time 变量的格式取决于你使用的 Nginx 版本和配置。
在 Nginx 1.9.11 及以后版本中,$time 变量的格式为 Unix 时间戳(例如 1648209600)。在早期版本中,它可能是一个字符串,表示当前时间(例如 “03/Apr/2022:13:15:02 +0000”)。
你可以使用 $time 变量来记录访问日志的时间,或者在其他需要当前时间的配置中使用它。例如,你可以将 $time 变量用于 log_format 指令,以便在访问日志中记录当前时间:

log_format custom_format '$remote_addr - $remote_user [$time] "$request" $status $body_bytes_sent';
此外,你还可以使用 $time 变量与其他内置变量结合,实现更复杂的功能。例如,你可以使用 $time 变量和 if 指令来限制某个时间段内的访问:

location /restricted {
    if ($time > 1648209600) {
        return 403;
    }
    # 其他配置
}
在这个例子中,如果当前时间大于 1648209600(即 2022 年 4 月 3 日 10:00:00),则返回 403 错误。否则,执行其他配置
要根据时间段开关某个Nginx配置项,可以使用Nginx的map指令和$time变量。以下是一个示例,演示如何在每天的8:00至20:00之间关闭gzip压缩功能:

http {
    map $time $disable_gzip {
        ~^([01][0-9]|2[0-3]):[0-5][0-9]$ 1;
        default 0;
    }

    server {
        listen 80;

        if ($disable_gzip = 1) {
            gzip off;
        } else {
            gzip on;
        }

        # ...其他配置项...
    }
}
在这个示例中,我们使用map指令创建了一个名为$disable_gzip的变量。该变量根据$time变量的值来判断是否应该关闭gzip压缩功能。$time变量包含了当前时间的小时和分钟信息。我们使用正则表达式~^([01][0-9]|2[0-3]):[0-5][0-9]$来匹配8:00至20:00之间的所有时间。如果匹配成功,$disable_gzip变量的值将设置为1,否则为0。

在server块中,我们使用if指令来检查$disable_gzip变量的值。如果该变量的值为1,我们将关闭gzip压缩功能;否则,我们将启用gzip压缩功能。

通过这种方式,您可以根据时间段开关Nginx的任何配置项。只需将相应的配置项放入if块中,并根据需要修改map指令即可