nginx map指令

nginx map指令用于根据现有的变量的值来赋值新变量。如根据x-forwarded-forremote_addr的值,创建新变量clientip

用法解析

Syntax: map string $variable { … }
Default: —
Context: http

  • string可以是一个或多个变量组成的字符串
  • $variable是新变量名
  • {...}中的内容为sourceresulting的映射
    • source可以为字符串或正则(~区分大小写,~*不区分大小写)
    • resulting赋予$variable新变量的值
  • {...}中可以使用以下关键字,当source与关键字重复时需要使用\转义
    • default value 设置默认值
    • hostnames 指明source的值是主机名,主机名可包含前缀或后缀
    • include file 包含变量文件
    • volatile 指明变量不可缓存

实例演示

获取client真实ip

nginx http区块配置如下:

    map $http_x_forwarded_for $clientip {
        "" $remote_addr;
        default $http_x_forwarded_for;
    }
    log_format  main  '$clientip - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$request_time"';

在客户端访问两次:

# curl -H 'x-forwarded-for:10.0.1.60' 10.2.1.105/f5.html
# curl 10.2.1.105/f5.html

访问日志:

10.0.1.60 - - [14/Aug/2019:18:37:44 +0800] "GET /f5.html HTTP/1.1" 200 2 "-" "curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "0.000"
10.0.1.60 - - [14/Aug/2019:18:37:58 +0800] "GET /f5.html HTTP/1.1" 200 2 "-" "curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "0.000"

这种办法有一个bug,如果客户端伪造了x-forwarded-for头部,后端主机的日志就没有参考价值了。

推荐在前端代理服务器上将x-forwarded-for重置为空之后再赋值。

转发到手机端页面

nginx http区块配置如下:

    map $http_user_agent $ifmobile {
        ~*iphone 1;
        ~*ipod 1;
        ~*android 1;
        default 0;
    }

nginx server区块配置如下:

        if (-f $request_filename/index.html) {
            rewrite ^(.*) $1/index.html;
        }

        if ( $ifmobile = 1 ) {
            rewrite (.*) /m$1;
        }

注:这里rewrite语句干扰了index语句的执行,在访问目录时,无法正确定位到目录下的index.html,故加了$request_filename/index.html的判断。

在客户端访问:

# curl -H 'user-agent:huaweimate20 android 9.0' 10.2.1.105/index.html
m/index.html
# curl -H 'user-agent:no' 10.2.1.105/index.html
index.html
# curl  10.2.1.105
index.html

上述需求也可以在nginx server区块使用以下配置来实现:

        if ( $http_user_agent ~* (iphone|ipod|android) ) {
            set $ifmobile 1;
        }

        if (-f $request_filename/index.html) {
            rewrite ^(.*) $1/index.html;
        }

        if ( $ifmobile = 1 ) {
            rewrite ^/(.*) /m/$1;
        }

匹配hostname

nginx http区块配置如下:

    map $http_referer $ifmyreferer {
        hostnames;
        *.example.com 1;
        example.com 1;
        .example.cn 1;
        default 0;
    }

    log_format  main  '$clientip - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$request_time" "$ifmyreferer"';

其中以下两行

*.example.com 1;
example.com 1;

可以简写为

.example.com 1;

前缀可以这样简写,后缀就不行了。

在nginx server区块添加以下配置,就可以防盗链了:

        location ~* \.(jpg|jpeg|png|gif|ico)$ {
            if ($ifmyreferer = 0) {
                return 404;
            }
        }

客户端请求:

# curl -H 'referer:www.example.com' 10.2.1.105/luozhao.jpg
GIF89aÿÿÿ!?L;
# curl -H 'referer:www.baidu.com' 10.2.1.105/luozhao.jpg
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

注:防盗链有专用指令valid_referers。

你可能感兴趣的:(nginx,nginx)