一  Nginx变量

Nginx 的'配置文件'使用的就是一门'微型的编程语言'

在 'nginx 配置中','变量'只能存放'一种类型的值',因为也只存在一种类型的值,那就是'字符串'

(1)设置变量

举例:'nginx.conf 文件'中有下面这一行配置:

set $var "hello world";

特点:我们看到,'Nginx 变量名'前面'有一个 $ 符号',这是'语法上'的要求

强调:所有的 'Nginx 变量'在 Nginx 配置文件中'引用时都须带上 $ 前缀',这种表示方法和'Perl、PHP' 这些语言是'相似'的

标准 ngx_rewrite 模块的 set 配置指令进行了赋值操作

(2)变量插值构造新字符串

①    把变量嵌入字符串常量中以构造出新的字符串

set $a hello;

set $b "$a, $a";

解释:通过'已有的 Nginx 变量 $a' 的值来'构造'变量 $b 的值,于是'这两条指令顺序'执行完之后,$a 的值是hello,而 $b 的值则是 hello, hello.

备注:这种技术在 Perl 世界里被称为"变量插值"(variable interpolation),它让专门的'字符串拼接'运算符

②    使用第三方 ngx_echo 模块的 echo 配置指令

强调:'并非'所有的配置指令都支持"变量插值",事实上'指令参数'是否允许"变量插值",'取决于'该指令的实现模块

+++++++++++'分割线'+++++++++++

需求:将 $foo 变量的值作为'当前请求的响应体'输出

我们看到,'echo 配置指令'的参数也支持"变量插值"

备注:echo模块'默认没有加载',需要'自己编译'然后配置
server {
        listen 8080;
 
        location /test {
            set $foo hello;
            # 需要安装ngx_echo模块
            echo "foo: $foo";
        }
    }

③    消除歧义

server {
        listen 8080;
        location /test {
            set $first "hello ";
            echo "${first}world";
        }
  }
说明:当'引用的变量名'之后'紧跟着变量名'的构成字符时(比如后跟'字母、数字以及下划线'),我们就需要使用'特别的记法'来'消除歧义'

解释:在 echo 配置指令的参数值中'引用变量 $first' 的时候,后面'紧跟着 world' 这个单词,所以如果直接写作 "$firstworld" 则 Nginx "变量插值"计算引擎会将之'识别为引用了变量 $firstworld'

解决策略:为了解决这个难题,Nginx 的字符串记法支持'使用花括号在 $ 之后把变量名'围起来

④    不创建变量直接使用

set 指令不仅有'赋值'的功能,它还有'创建 Nginx 变量的副作用',即当作为'赋值对象'的变量尚'不存在'时,它会'自动创建'该变量

++++++++++++++++'分割线'++++++++++++++++

set $b "$a, $a";

举例:如果 $a 这个变量'尚未创建',则 set 指令'会自动'创建 $a 这个'用户变量',如果我们'不创建'就'直接使用'它的值则会'报错'
​
server {
     listen 8080;
    
     location /bad {
         # 注意这个配置的'报错' -->'不创建'则'直接使用'
         echo $foo;
     }
 }

++++++++++++++++'报错提示'++++++++++++++++

此时 Nginx 服务器会'拒绝'加载配置: '[emerg] unknown "foo" variable'

⑤    proxy_set_header

补充知识点

代理转发:proxy_set_header是用来'设置请求头'的,设置了请求头后,'后端服务器'就可以'获取'到这些变量值

备注1: Host、X-Real-IP、X-Forwarded-For -->'标准的'HTTP请求头-->'RFC规范'定义

备注2: 可以'自定义'HTTP请求头

+++++++++++++++++'设置方式'+++++++++++++++++

proxy_set_header   X-Real-IP        $remote_addr;

proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

proxy_set_header   Host             $http_host; #$proxy_host

proxy_set_header   X-NginX-Proxy    true;

proxy_set_header   Connection "";

⑥    细节

Nginx '变量的创建'和'赋值操作'发生在全然'不同的时间阶段'

1)Nginx '变量的创建'只能发生在 'Nginx 配置加载'的时候,或者说 'Nginx 启动'的时候;

2)而'赋值操作'则只会发生在'请求实际处理'的时候;

小结:这意味着'不创建而直接使用变量'会导致'启动失败',同时也意味着我们'无法在请求处理时动态地'创建新的 Nginx 变量

⑦    变量作用域

Nginx 变量一旦创建,其'变量名的可见范围'就是'整个 Nginx 配置',甚至可以'跨越不同虚拟主机'的 server配置块

+++++++++++++'案例讲解'+++++++++++++

server {
        listen 8080;
 
        location /foo {
            echo "foo = [$foo]";
        }
 
        location /bar {
            set $foo 32;
            echo "foo = [$foo]";
        }
    }

'location /bar' 中用 set 指令创建了变量 $foo,于是在'整个配置文件中'这个变量都是可见的,因此我们可以在 'location /foo' 中'直接引用'这个变量而'不用担心 Nginx 会报错'

+++++++++++++++++'结论'+++++++++++++++++

自己理解:变量与请求强相关,如果在'location'定义变量,其它location也'可以直接引用',但是变量值为'空串'

Nginx 变量名的'可见范围'虽然是整个配置,但'每个请求'都有'所有变量的独立副本',或者说都有各变量用来存放值的容器的'独立副本',彼此'互不干扰'

比如:'上面的案例'我们请求了/bar 接口后,$foo 变量被赋予了值 32,但它'丝毫不会影响'后续对 /foo 接口的请求所对应的 $foo 值(它'仍然是空'的!),因为各个请求都'有自己独立的 $foo 变量的副本'

重点:Nginx 变量在请求之间'不是全局共享'的东西、或者说'全局变量','Nginx 变量的生命期'是'不可能跨越请求'边界的

(2)内置变量

①   官方内置变量文档

以"$"开头的变量都是'内置变量'

②    常用的内置变量

nginx 模块提供的"预定义变量",或者说'内建变量'(builtin variables)

参考链接1

参考链接2

参考链接3

参考链接4

$remote_addr;
  存放了'客户端的地址',注意是客户端的公网IP,也就是一家人访问一个网站,则会显示为'路由器的公网IP'

$args;
  变量中存放了'请求行中(GET请求)的参数',例如http://node101.yinzhengjie.org.cn/main/index.do?'id=20190221&partner=search'中的id=20190221&partner=search

$document_root;
  保存了针对'当前资源的请求'的'系统根目录',如/apps/nginx/html -->对应'root'指令

$document_uri;
  保存了当前请求中'不包含指令的URI',注意是'不包含请求'的指令,比如http://node101.yinzhengjie.org.cn/main/index.do?id=20190221&partner=search会'被定义为/main/index.do'

$host;
  存放了'请求的host名称'

$http_user_agent;
  '客户端浏览器'的详细信息

$http_cookie;
  '客户端的cookie'信息

limit_rate 10240;
echo $limit_rate;
  如果nginx服务器使用limit_rate配置了'显示网络速率',则会显示,如果'没有设置',则'显示0'

$remote_port;
  客户端请求Nginx服务器时'随机打开的端口',这是每个'客户端自己的端口'

$remote_user;
  已经'经过Auth Basic Module验证'的用户名

$request_body_file;
  做'反向代理'时发给'后端服务器的本地资源'的名称

$request_method;
  请求'资源的方式',GET、PUT、DELETE等

$request_filename;
  当前'请求的资源文件的路径'名称,由root或alias指令与URI请求生成的文件'绝对路径',如:/apps/nginx/html/main/index.html

$request_uri;
  包含'请求参数'的原始URI,'不包含主机名',如:/main/index.do?id=20190221&partner=search 

$scheme;
  请求的'协议',如ftp、https、http等

$server_protocol;
  保存了'客户端请求资源'使用的协议的版,如HTTP/1.0、'HTTP/1.1'、HTTP/2.0等

$server_addr;
  保存了'服务器的IP地址'

$server_name;
  请求的'服务器的主机名'

$server_port;
  请求的'服务器的端口号'

+++++++++++++++'补充知识点'+++++++++++++++

$arg_name           请求中的'name参数'-->请求的参数的名字,根据'具体情况'而定
$binary_remote_addr 远程地址的'二进制'表示
$body_bytes_sent    已发送的'消息体'字节数
$content_length     HTTP请求信息里的"Content-Length"
$content_type       请求信息里的"Content-Type"
$host               请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名
$http_referer       '引用地址'
$http_via           '最后'一个访问服务器的'ip地址'
$is_args            如果请求行'带有参数',返回"?",否则'返回空字符串'
$nginx_version      当前运行的nginx版本号
$pid                'worker进程'的PID
$query_string       与$args'相同'
$realpath_root      按root指令或alias指令算出的'当前请求的绝对路径',其中的'符号链接'都会解析成真是文件路径
$request            '用户请求'
$request_body       这个变量(0.7.58+)包含'请求的主要信息',在使用proxy_pass或fastcgi_pass指令的location中'比较有意义'
$request_body_file  客户端'请求主体'信息的'临时文件名'
$request_completion 如果'请求成功',设为"OK";如果'请求未完成'或者'不是'一系列请求中最后一部分则设为空
$request_filename   当前请求的文件路径名,比如/opt/nginx/www/test.php
$request_uri        请求的URI,'带参数'; 比如http://localhost:88/test1/
$uri                请求的URI,可能'和最初的值有不同',比如经过'重定向'之类的
$http_name          用来获取'任意请求头'的值

③    服务端打印nginx内置变量返回给客户端

++++++++++++++++++'调试使用的'++++++++++++++++++

location /main {
    index index.html;
    default_type text/html;
        echo "remote_addr = $remote_addr";
        echo "******";
        echo "args = $args";
        echo "******";
        echo "document_root = $document_root";
        echo "******";
        echo "document_uri = $document_uri";
        echo "******";
        echo "host = $host";
        echo "******";
        echo "http_user_agent = $http_user_agent";
        echo "******";
        echo "http_cookie = $http_cookie"
        echo "******";
        limit_rate 10240;
        echo "limit_rate = $limit_rate";
        echo "******";
        echo "remote_prot = $remote_port";
        echo "******";
        echo "remote_user = $remote_user";
        echo "******";
        echo "request_body_file = $request_body_file";
        echo "******";
        echo "request_method = $request_method";
        echo "******";
        echo "request_filename = $request_filename";
        echo "******";
        echo "request_uri = $request_uri";
        echo "******";
        echo "scheme = $scheme";
        echo "******";
        echo "server_protocol = $server_protocol";
        echo "******";
        echo "server_addr = $server_addr";
        echo "******";
        echo "server_name = $server_name";
        echo "******";
        echo "server_port = $server_port";
        echo "******";
    }

nginx变量漫谈

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐