这是一个很好的问题,能问到这个深度,说明你已经从“会用”开始迈向“理解”了。
一句话回答:指令是“动作”,变量是“信息”。
- 指令:你告诉 Nginx 要做什么(比如:
proxy_pass表示要转发,rewrite表示要重写)。 - 变量:你告诉 Nginx 用什么信息来做(比如:用
$remote_addr记录客户端IP,用$request_uri匹配路径)。
我用一个表格和几个实例来帮你彻底理清它们的关系。
一、核心区别
| 维度 | 指令 (Directive) | 内置变量 (Built-in Variable) |
|---|---|---|
| 角色 | 动词(下达命令) | 名词(提供信息) |
| 本质 | Nginx 的配置项,驱动功能模块工作 | Nginx 内部维护的数据字段,动态变化的 |
| 语法 | 关键字 + 参数 + ;,如:gzip on; | 以 $ 开头,如:$host |
| 存在位置 | 写在 nginx.conf 里,是配置的主体 | 可以在配置值、条件判断、日志格式中被引用 |
| 谁定义 | 由 Nginx 的各个模块定义(如 ngx_http_proxy_module 定义了 proxy_pass) | 由 Nginx 核心或模块在运行时提供(如 HTTP 模块提供 $http_user_agent) |
| 示例 | proxy_pass、rewrite、set、if | $remote_addr、$uri、$args、$http_cookie |
二、它们的“关系”是什么?
它们是“控制流”与“数据”的关系。指令负责逻辑和动作,变量为这些动作提供输入、上下文和输出目标。
我用几个你熟悉的 Nginx 配置片段来解释它们的配合:
关系 1:变量作为指令的“参数”
这是最直接的关系。指令的值,可以是一个具体的字符串,也可以是一个包含变量的表达式。
# 变量 $host 作为 proxy_pass 指令的参数
proxy_pass http://backend_$host;
# 变量 $remote_addr 作为 add_header 指令的参数
add_header X-Real-IP $remote_addr;
关系 2:变量在 if 指令中作为“判断条件”
if 是逻辑判断指令,它判断的对象,就是变量。
# 判断 $http_user_agent 这个变量是否匹配正则
if ($http_user_agent ~* "mobile") {
# 这里的 rewrite 是另一个指令
rewrite ^(.*)$ /mobile/$1 last;
}
关系 3:用 set 指令“创建或修改变量”
set 是一个用来操作变量的指令。你可以用它来创建自定义变量,或者修改现有变量的值,供后续指令使用。
# 创建一个新变量 $flag,并赋值为 0
set $flag 0;
# 根据条件修改变量值
if ($request_method = POST) {
set $flag "${flag}1";
}
# 后续的 proxy_pass 或其他指令可以引用 $flag
关系 4:变量在 log_format 指令中定义“日志格式”
log_format 是一个用来定义日志模板的指令,它的模板内容就是由各种变量组成的。
# log_format 指令定义日志里要记录哪些变量
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
三、总结
| 指令 | 变量 |
|---|---|
proxy_pass | $host (告诉它转给谁) |
if | $request_method (告诉它判断什么) |
rewrite | $1, $2 (告诉它替换成什么) |
set | 操作变量本身 (它就是用来定义或修改变量的) |
log_format | $time_local (告诉它记录什么) |
你可以这样理解:指令是 Nginx 配置的“骨架”,搭建起整个处理流程;变量是流淌在骨架里的“血液”,为每一个环节提供动态的、实时的信息。 你现在能写出灵活的配置,正是因为理解了如何用指令去驾驭这些变量。
发表回复