我眼中的 Nginx(三):Nginx 变量和变量插值
张超:又拍云系统开发高级工程师,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,活跃于 OpenResty 社区和 Nginx 邮件列表等开源社区,专注于服务端技术的研究;曾为 ngx_lua 贡献源码,在 Nginx、ngx_lua、CDN 性能优化、日志优化方面有较为深入的研究。
如果读者曾配置过 Nginx,那么一定知道 Nginx 允许我们在配置文件里嵌入”变量”,这些变量由 Nginx 的各个模块定义,其目的是为了提升配置的灵活性,如这一段配置:
location = /t {
set $my_addr "127.0.0.1:8081";
proxy_pass http://$my_addr/index.html;
}
我们可以通过操作变量 $my_addr 来动态指定 upstream。
认识 Nginx 变量
Nginx 的变量和 perl、php 等语言的类似,由美元符号 $ 开头,随后跟着一个字符串,代表这个变量的名称,例如 $name,可选地,这个字符串可以用花括号包围,譬如 ${name} 。在 Nginx 世界里,合法的变量名可用字符集为 [a-zA-Z0-9_],特别地,Nginx 支持正则子组,即 $1,$2 这样的变量。注意变量值只有字符串这一种类型。
另外还存在一类特殊的变量,它们的名称是不固定的,更确切地说,它们描述的是一群变量。譬如 $http_,描述对应请求的请求头;$sent_http 则描述对应请求的响应头。
在实现上,一个变量由其名称、读/取处理程序和一些标志位组成。这些标志位定义了变量的属性,例如表明一个变量是否可缓存、是否可进行索引。
变量拥有两种存放方式,第一种是储存在一个全局的 hash 表里,使用该变量时需要进行查询;第二种则是储存在一个全局动态数组里,每个变量存在一个唯一的索引。相比较而言,第二种方式在性能上更加优秀,因为它不需要计算 hash key,也不需要查找 hash 表。
变量解析是运行时的。即惰性求值,而且通常变量解析总是和请求绑定的,因此变量信息虽然只有一份,但是变量值却会有多份。
前面提到,变量是可缓存的,Nginx 模块开发者们可以视情况决定变量的可缓存性,如果一个变量设定为可缓存,则它在经历第一次求值后,其求值结果会被缓存起来,后续使用到该变量时会直接获取到缓存里的值。譬如,Nginx 的 map 模块就把变量设置为可缓存,因为在它看来这样的一次变量获取操作是足够昂贵的。
谨慎对待变量缓存。笔者曾遇到过一个因为变量缓存引起的问题: $host 这个变量,该变量也是可缓存的。根据文档里的描述,这个变量的取值顺序为:
in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request
通常情况下,我们可以使用 $host 获取到请求头里的 Host,然而因为它的可缓存性,该变量无法体现 Host 头部的改动,比如下面的代码:
local old_host = ngx.var.host
ngx.req.set_header("Host", "foo.example.com")
local new_host = ngx.var.host
new_host的值将和 old_host 一样,而非直觉上所想的 http://foo.example.com。
另外,在原生 Nginx 的实现里,主/子请求共享同一份变量缓存。如果子请求使用了某个变量,并且该变量值被缓存下来,那么主请求之后访问该变量时,就会得到子请求所产生的缓存拷贝。当然,如果模块开发者自己定义子请求的创建,也是可以绕过这一点的。譬如 ngx_lua 在创建子请求的 API 里就提供了是否指定主/子请求共享变量的选项。
变量插值
用户的需求总是多变的。譬如在使用 upstreamcache 功能(另外一个典型的例子就是 access_log)时,通常需要设计一个良好的缓存 key,此时需要考虑到的因素可能有多个,即我们的 key 不会单单由一个变量或者常量组成,而是需要设计成它们的结合体,如 mykey=$http_host&$uri&$args。
在实现上,Nginx 首先会把包含变量和常量的复杂字符串转换成一种中间形式。具体来说,Nginx 会把这个字符串按变量和常量进行拆分,分别为它们进行“包装”(包括设置好对应的取值回调函数),之后按顺序放入一个动态数组,这个动态数组就是中间形式了。
比如上段提到的缓存 key,经过处理后,得到的动态数组是这样的:

拆分的处理是在具体指令解析阶段完成的。真正取值发生在具体请求的运行当中,通过执行该动态数组每个成员的取值回调函数,将单一的值拼装在一起,最终就实现了变量插值。
发散
借鉴 Nginx 的变量插值,笔者不久前用 Golang 实现了一个小玩意(tokers/corgi),当然,还是为了好玩 :)。
变量插值的思想非常值得学习,如果能利用好这一点,程序设计上就会变得更加灵活。
推荐阅读:
我眼中的 Nginx(三):Nginx 变量和变量插值的更多相关文章
- 快速掌握Nginx(三) —— Nginx+Systemd托管netcore应用
以前dotnet web应用程序开发完成后,我们都是使用IIS部署在Windows Server上,如今netcore技术发展迅速,因为其跨平台的特性,将dotnet web应用程序部署在更方便部署和 ...
- Nginx(三):日志文件管理
一.Nginx日志描述 通过访问日志,你可以得到用户地域来源.跳转来源.使用终端.某个URL访问量等相关信息: 通过错误日志,你可以得到系统某个服务或server的性能瓶颈等.因此,将日志好好利用,你 ...
- linux 安装nginx -查看 linux的环境变量
我发现在linux上面安装linux很简单 在CentOS release 6.5 上面先看一下操作系统的版本: lsb_release -a 直接执行 yum install nginx 系统自动的 ...
- Nginx教程(三) Nginx日志管理
Nginx教程(三) Nginx日志管理 1 日志管理 1.1 Nginx日志描述 通过访问日志,你可以得到用户地域来源.跳转来源.使用终端.某个URL访问量等相关信息:通过错误日志,你可以得到系统某 ...
- nginx(三)反向代理和负载均衡
nginx(三)反向代理和负载均衡 正向代理概念:比如在学校要上网,在学校内网是一个内网ip,需要连上公网就需要一个正向代理服务器. 反向代理概念: 看下图(Nginx只做请求的转发,后台有多个htt ...
- 【nginx】nginx配置文件结构,内置变量及参数调优
Nginx的配置文件是一个纯文本文件,它一般位于Nginx安装目录的conf目录下,整个配置文件是以block的形式组织的.每个block一般以一个大括号“{”来表示.block 可以分为几个层次,整 ...
- 使用正则表达式来截取nginx中的内置变量
nginx 中的内置变量都可以通过 if 指令 + 正则表达式来进行截取,截取之后的结果通过正则表达式的分组来进行引用 比如:从请求中传过来的一个名为 ssl_client_s_dn 的变量,它的值是 ...
- Nginx三种模式的虚拟主机(附Apache基于域名的虚拟主机)
1.安装nginx # pcre中文"perl兼容正则表达式",安装pcre库是为了让nginx支持具备URL重写功能 # 的Rewrite模块,rewrite可以实现动态页面转成 ...
- nginx多层反代配置变量proxy_set_header
Nginx多层反代配置变量proxy_set_header过程记录 第一层代理: (1)路径: $ vim /data/soft/nginx/conf/vhost/xixi.conf (2)内容:(注 ...
随机推荐
- 搭建第一个spring boot项目
一.开发工具建议使用Spring Tool Suite 下载地址:http://spring.io/tools/sts/all/ 点击versions选择相应的版本下载,解压后直接运行即可. 二.创建 ...
- C#高级编程笔记之第三章:对象和类型
类和结构的区别 类成员 匿名类型 结构 弱引用 部分类 Object类,其他类都从该类派生而来 扩展方法 3.2 类和结构 类与结构的区别是它们在内存中的存储方式.访问方式(类似存储在堆上的引用类型, ...
- mysql 基本命令操作
1. 查看存储引擎 show engines; 2. 查看数据存储位置 show variables like 'datadir': 3. 存储引擎 create table mytest engin ...
- IAAS-虚拟化技术组件介绍
虚拟化技术组件涉及众多,下面对一些组件所处的层级以及定位做个简单的汇总介绍,部分信息来自于网络整理,如有不准确之处,请指正.
- hdu-2683 TCE-frep number system---完全数+二项展开式
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2683 题目大意: g(n)是n的因子和 两种操作: A a b 查询a b区间有多少个n满足上式. ...
- 微信小程序-获取经纬度
微信小程序-获取经纬度 最近公司新功能 要求在外的市场人员 发送位置信息回来. 用的还是微信小程序开发.... 微信小程序 提供一个接口 getLocation 这个接口反回来的位置 相对实际位置 相 ...
- MongoDB学习--安装与管理
一.简介 MongoDB是一种强大.灵活,且易于扩展的通用型数据库.他能扩展出非常多的功能.如二级索引(secondary index).范围查询(range query).排序.聚合(aggrega ...
- Python之深浅拷贝
拷贝就是拷贝,何来深浅之说? Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果 其实这个是由于共享内存导致的结果 浅拷贝 l1 = [1,2,3 ...
- 基于Spring Cloud、JWT 的微服务权限系统设计
基于Spring Cloud.JWT 的微服务权限系统设计 https://gitee.com/log4j/pig https://github.com/kioyong/spring-cloud-de ...
- Navicat PatchNavicat
Navicat for MySQL 11.0.10 32+64位(内含破解补丁)\64位 安装完成后,退出Navicat 执行PatchNavicat.exe,提示patch完成后,Navicat即可 ...