Nginx 内置变量详解:从原理到实战案例

Nginx 内置变量是 Nginx 配置中极具灵活性的核心特性,它们能动态获取请求、连接、服务器等维度的实时数据,让配置从"固定模板"升级为"智能响应"。本文将系统梳理常用内置变量的分类、含义,并结合实战案例说明其应用场景,帮助你真正用好 Nginx 变量。

一、Nginx 内置变量的核心特性

在深入变量前,先明确两个关键特性:

  1. 动态性 :变量值并非固定,而是在每次请求处理时实时生成(如 $remote_addr 会随客户端 IP 变化)。
  2. 作用域:变量仅在当前请求的处理周期内有效,不同请求的变量值相互独立。
  3. 命名规则 :所有内置变量均以 $ 开头,如 $uri$status

二、常用内置变量分类与含义

按"数据来源"可将内置变量分为 5 大类,涵盖请求、连接、服务器、响应等核心场景。

1. 请求相关变量(获取客户端请求信息)

这类变量用于获取客户端发送的请求细节,是最常用的变量类型。

变量名 含义 示例
$remote_addr 客户端真实 IP 地址(未经过代理时) 192.168.230.1(本地局域网 IP)
$arg_xxx 获取 URL 中 xxx 对应的参数值(xxx 为参数名) 请求 http://xxx/?id=123 时,$arg_id=123
$args 完整的 URL 请求参数(? 后面的所有内容) 请求 http://xxx/?id=123&name=test 时,$args=id=123&name=test
$request_method 客户端请求方法(GET/POST/PUT/DELETE 等) GETPOST
$request_uri 完整的请求 URI(包含路径和参数,不包含域名) 请求 http://xxx/api/user?uid=1 时,$request_uri=/api/user?uid=1
$uri / $document_uri 请求的 URI 路径(不含参数,两者功能几乎一致) 请求 http://xxx/api/user?uid=1 时,$uri=/api/user
$http_xxx 获取请求头中 xxx 字段的值(xxx 为请求头名,需将 - 改为小写) 获取 User-Agent 时用 $http_user_agent,获取 Referer 时用 $http_referer
$cookie_xxx 获取客户端 Cookie 中 xxx 对应的 value 客户端 Cookie 为 token=abc123 时,$cookie_token=abc123

2. 连接相关变量(获取网络连接信息)

用于获取客户端与服务器之间的连接状态,常用于连接追踪和并发控制。

变量名 含义 示例
$connection 客户端与服务器的唯一连接 ID(每次新连接会生成新 ID) 12345(数字型 ID)
$connection_requests 当前连接上已处理的请求次数(长连接场景下会累计) 同一连接发起第 3 次请求时,值为 3
$remote_port 客户端用于连接的端口号 54321(客户端随机端口)
$server_port 服务器监听的端口号(当前请求命中的端口) 80(HTTP)、443(HTTPS)

3. 服务器相关变量(获取服务器自身信息)

用于获取 Nginx 服务器的配置和系统信息,常用于多服务器部署场景。

变量名 含义 示例
$server_addr 服务器处理当前请求的 IP 地址(多网卡时对应绑定的 IP) 192.168.230.130(服务器内网 IP)
$server_name 当前请求命中的 server 块的 server_name 配置值 server_name www.example.com,则值为 www.example.com
$hostname 服务器的系统主机名(与 hostname 命令输出一致) centos-nginx-server

4. 响应相关变量(获取 Nginx 响应信息)

用于记录 Nginx 向客户端返回的响应数据,常用于日志统计和性能分析。

变量名 含义 示例
$status 响应的 HTTP 状态码 200(成功)、404(未找到)、502(网关错误)
$body_bytes_sent 发送给客户端的响应体大小(单位:字节,不含响应头) 返回 1KB 文本时,值为 1024
$bytes_sent 发送给客户端的总字节数(含响应头 + 响应体) 通常比 $body_bytes_sent 大 100-200 字节(响应头占比)
$request_time 请求的总处理耗时(单位:秒,精确到毫秒) 0.005(表示 5 毫秒)

5. 时间相关变量(获取时间信息)

用于记录请求处理的时间,常用于日志时间戳和时间范围控制。

变量名 含义 示例
$msec 请求处理完成时的 Unix 时间戳(含毫秒,从 1970-01-01 开始) 1724325600.123(对应 2024-08-22 11:20:00.123)
$time_local 服务器本地时间(格式化字符串,含时区) 22/Aug/2024:11:20:00 +0800+0800 表示北京时间)
$time_iso8601 ISO 8601 标准时间(UTC 时间,无时区偏移) 2024-08-22T03:20:00+00:00

三、内置变量实战案例

了解变量含义后,关键是知道"在什么场景用什么变量"。以下 5 个实战案例覆盖日志、鉴权、跳转、限流等高频场景。

案例 1:自定义访问日志(记录关键请求信息)

默认的 Nginx 访问日志仅包含基础信息,通过变量可自定义日志格式,记录如"客户端 IP、请求方法、参数、耗时"等关键数据,方便后续分析。

配置步骤:

  1. nginx.confhttp 块中定义日志格式:

    nginx 复制代码
    http {
        # 1. 定义自定义日志格式(命名为 "detail_log")
        log_format  detail_log  '$remote_addr [$time_local] "$request_method $request_uri" '
                               'status:$status args:"$args"耗时:$request_time '
                               'user_agent:"$http_user_agent"';
        
        # 2. 启用自定义日志(指定日志路径和格式)
        access_log  /usr/local/nginx/logs/detail_access.log  detail_log;
        
        # 其他配置...
    }
  2. 重载 Nginx 配置:

    bash 复制代码
    /usr/local/nginx/sbin/nginx -t  # 检查语法
    /usr/local/nginx/sbin/nginx -s reload  # 重载生效

日志效果:

访问 http://192.168.230.130/?id=123 后,日志文件会生成如下记录:

ini 复制代码
192.168.230.1 [22/Aug/2024:11:30:00 +0800] "GET /?id=123" status:200 args:"id=123"耗时:0.002 user_agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/127.0.0.1"

案例 2:URL 参数鉴权(限制特定参数访问)

场景:仅允许 token 参数为 abc123 的请求访问 /admin 路径,否则返回 403 禁止访问。

配置步骤:

server 块中添加 location 规则:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    
    # 匹配 /admin 路径
    location /admin {
        # 1. 检查 $arg_token(URL 中 token 参数)是否等于 abc123
        if ($arg_token != "abc123") {
            return 403 "Forbidden: Invalid token\n";  # 不匹配则返回 403
        }
        
        # 2. 匹配通过时的处理(如返回 admin 页面)
        default_type text/html;
        return 200 "<h1>Admin Page (Token Valid)</h1>";
    }
}

测试效果:

  • 合法请求:http://192.168.230.130/admin?token=abc123 → 返回 200 和 Admin 页面。
  • 非法请求:http://192.168.230.130/admin?token=wrong → 返回 403 和 "Forbidden"。

案例 3:根据客户端 IP 跳转(本地 IP 免验证)

场景:局域网 IP(192.168.230.xxx)访问 /login 时直接跳转至首页,其他 IP 正常显示登录页。

配置步骤:

利用 $remote_addr 判断客户端 IP,结合 rewrite 实现跳转:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    
    location /login {
        # 1. 匹配局域网 IP(以 192.168.230. 开头)
        if ($remote_addr ~* ^192\.168\.230\.) {
            rewrite ^/login$ / permanent;  # 301 永久跳转到首页
        }
        
        # 2. 其他 IP 显示登录页
        default_type text/html;
        return 200 "<h1>Login Page (Non-Local IP)</h1>";
    }
    
    # 首页配置
    location / {
        default_type text/html;
        return 200 "<h1>Home Page (Local IP Bypassed Login)</h1>";
    }
}

测试效果:

  • 本地 IP(如 192.168.230.1)访问 /login → 自动跳转到 /(首页)。
  • 外部 IP(如 10.0.0.1)访问 /login → 显示登录页。

案例 4:根据请求头切换后端服务(前后端分离场景)

场景:请求头 X-Request-Typeapi 时,转发请求到后端 API 服务(127.0.0.1:8080);否则返回静态页面。

配置步骤:

利用 $http_x_request_type 获取自定义请求头,结合 proxy_pass 实现反向代理:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    
    location / {
        # 1. 判断请求头 X-Request-Type 是否为 api
        if ($http_x_request_type = "api") {
            proxy_pass http://127.0.0.1:8080;  # 转发到 API 服务
            proxy_set_header Host $host;  # 传递 Host 头给后端
            break;  # 跳出 if,避免后续执行
        }
        
        # 2. 其他请求返回静态首页
        root /usr/local/nginx/html;
        index index.html;
    }
}

测试效果:

  • 发送 API 请求(带请求头):

    bash 复制代码
    curl -H "X-Request-Type: api" http://192.168.230.130/api/user

    → 请求被转发到 127.0.0.1:8080/api/user

  • 普通访问:http://192.168.230.130 → 返回 /usr/local/nginx/html/index.html

场景:Cookie 中 version=beta 的用户访问 /feature 时,返回新功能页面;其他用户返回旧页面。

配置步骤:

利用 $cookie_version 获取 Cookie 值,实现灰度分流:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    
    location /feature {
        default_type text/html;
        
        # 1. 检查 Cookie 中 version 是否为 beta
        if ($cookie_version = "beta") {
            return 200 "<h1>New Feature (Beta Version)</h1>";  # 新功能
        }
        
        # 2. 其他用户显示旧功能
        return 200 "<h1>Old Feature (Stable Version)</h1>";
    }
}

测试效果:

  • 灰度用户(带 Cookie):

    bash 复制代码
    curl -b "version=beta" http://192.168.230.130/feature

    → 返回 "New Feature (Beta Version)"。

  • 普通用户(无 Cookie):

    bash 复制代码
    curl http://192.168.230.130/feature

    → 返回 "Old Feature (Stable Version)"。

四、使用内置变量的注意事项

  1. 避免过度使用 if 指令 :Nginx 的 if 指令在某些场景下可能触发意外行为(如与 try_files 冲突),复杂逻辑优先用 map 指令或 Lua 脚本。
  2. 代理场景下的 IP 问题 :若 Nginx 位于代理服务器后(如 CDN、负载均衡器),$remote_addr 会变为代理 IP,需通过 $http_x_forwarded_for 获取客户端真实 IP(需代理服务器传递该请求头)。
  3. 变量大小写敏感$arg_id$arg_ID 是两个不同的变量(前者对应 ?id=1,后者对应 ?ID=1),配置时需注意参数名大小写。
  4. 性能影响 :内置变量本身性能开销极低,但频繁使用复杂正则匹配(如 if ($remote_addr ~* ...))可能增加 CPU 消耗,高并发场景需优化正则。

五、总结

Nginx 内置变量是连接"静态配置"与"动态请求"的桥梁,掌握它们能让你摆脱固定配置的束缚,实现更灵活的请求处理逻辑。本文梳理的 5 大类变量和实战案例,覆盖了日志、鉴权、跳转、代理、灰度等高频场景,建议结合实际需求动手测试------只有在实践中反复使用,才能真正理解变量的威力。

如果需要更复杂的场景(如结合 map 指令批量处理变量、Lua 脚本扩展变量功能),可以进一步深入学习 Nginx 高级配置技巧。

相关推荐
当无8 分钟前
Mac 使用Docker部署Mysql镜像,并使用DBever客户端连接
后端
野生的午谦8 分钟前
PostgreSQL 部署全记录:Ubuntu从安装到故障排查的完整实践
后端
David爱编程42 分钟前
可见性问题的真实案例:为什么线程看不到最新的值?
java·后端
00后程序员1 小时前
移动端网页调试实战,iOS WebKit Debug Proxy 的应用与替代方案
后端
whitepure1 小时前
我如何理解与追求整洁代码
java·后端·代码规范
用户8356290780511 小时前
Java高效读取Excel表格数据教程
java·后端
yinke小琪1 小时前
今天解析一下从代码到架构:Java后端开发的"破局"与"新生"
java·后端·架构
码出极致1 小时前
支付平台资金强一致实践:基于 Seata TCC+DB 模式的余额扣减与渠道支付落地案例
后端·面试
掘金一周1 小时前
DeepSeek删豆包冲上热搜,大模型世子之争演都不演了 | 掘金一周 8.28
前端·人工智能·后端
静凇1 小时前
在 Ubuntu 24.04 和 Debian 12.10 中安装 Docker 和 Docker Compose,并使用轩辕镜像加速拉取镜像
后端