一、Nginx变量的基本概念与类型
在Nginx中,变量就像是我们日常生活中的"便签",可以临时存储各种信息。它们主要分为两种:内置变量和自定义变量。内置变量是Nginx自带的,比如$host代表请求的主机名,$uri表示当前请求的URI;而自定义变量则是我们通过set指令创建的,灵活性极高。
举个例子,我们可以在配置中这样使用内置变量:
server {
listen 80;
server_name example.com;
location / {
# 使用内置变量$host记录访问的域名
add_header X-Host-Name $host;
return 200 "Welcome to $host!";
}
}
而自定义变量的创建也很简单:
server {
listen 80;
server_name example.com;
# 定义一个变量$backend_server
set $backend_server "192.168.1.100";
location /api {
proxy_pass http://$backend_server;
}
}
注意:变量名区分大小写,且自定义变量仅在当前作用域有效。
二、动态配置的实现技巧
Nginx变量的真正威力在于它能实现动态配置。比如,我们可以根据请求参数动态改变代理目标:
server {
listen 80;
server_name example.com;
# 从查询参数中获取backend参数值
if ($arg_backend) {
set $backend_server $arg_backend;
}
location /dynamic {
# 动态代理到$backend_server
proxy_pass http://$backend_server;
}
}
这样,请求/dynamic?backend=192.168.1.101就会被代理到192.168.1.101。
另一个常见场景是根据用户的地理位置动态返回内容。我们可以结合geoip模块:
http {
geoip_country /usr/share/GeoIP/GeoIP.dat;
server {
listen 80;
server_name example.com;
# 根据国家代码设置变量
set $country_code $geoip_country_code;
location / {
# 根据国家返回不同内容
if ($country_code = "CN") {
return 200 "你好,中国用户!";
}
return 200 "Hello, World!";
}
}
}
三、灵活路由控制的实现
利用变量,我们可以实现复杂的路由逻辑。比如,基于用户代理的路由:
map $http_user_agent $route {
default "default";
"~*iPhone" "mobile";
"~*Android" "mobile";
"~*iPad" "tablet";
}
server {
listen 80;
server_name example.com;
location / {
# 根据设备类型路由
if ($route = "mobile") {
proxy_pass http://mobile_backend;
}
if ($route = "tablet") {
proxy_pass http://tablet_backend;
}
proxy_pass http://default_backend;
}
}
更复杂的场景是A/B测试。我们可以通过cookie实现:
server {
listen 80;
server_name example.com;
# 检查ab_test cookie
set $ab_group "A";
if ($cookie_ab_test) {
set $ab_group $cookie_ab_test;
}
location / {
# 根据ab_group路由
if ($ab_group = "A") {
proxy_pass http://backend_a;
}
if ($ab_group = "B") {
proxy_pass http://backend_b;
}
proxy_pass http://backend_a;
}
}
四、高级技巧与性能优化
变量虽然强大,但滥用会影响性能。比如,避免在频繁执行的location中使用复杂变量计算:
server {
listen 80;
server_name example.com;
# 不推荐:每次请求都计算
location /bad {
set $sum 0;
set $i 0;
while ($i < 100) {
set $sum $sum+$i;
set $i $i+1;
}
return 200 "Sum is $sum";
}
# 推荐:预计算
location /good {
# 假设sum已预先计算好
set $pre_sum 4950;
return 200 "Sum is $pre_sum";
}
}
另一个技巧是使用map指令创建变量映射表,比多个if更高效:
map $uri $custom_header {
default "default";
"/special" "special_case";
"/vip" "vip_user";
}
server {
listen 80;
server_name example.com;
location / {
add_header X-Custom $custom_header;
proxy_pass http://backend;
}
}
五、应用场景与注意事项
应用场景:
- 多租户系统:根据域名动态选择后端
- 灰度发布:通过cookie或header路由流量
- 地域化内容:基于地理位置返回不同内容
- 设备适配:针对不同设备优化体验
技术优缺点:
- 优点:灵活、无需重启生效、可与其他模块配合
- 缺点:复杂逻辑影响性能、调试困难
注意事项:
- 变量作用域要清晰
- 避免在变量中使用Nginx指令
- 谨慎使用
if,它有自己的作用域规则 - 性能敏感场景要测试变量计算开销
六、总结
Nginx变量就像一把瑞士军刀,用好了能让配置变得极其灵活。从简单的动态代理到复杂的路由策略,变量都能优雅地解决问题。关键是要理解其工作原理,在灵活性和性能之间找到平衡。