agentzh nginx变量漫谈随手记
文章地址:https://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
- Nginx 变量名前面有一个 $ 符号
1 2
| set $a "b"; set $b "$a, $a";
|
- 有没有办法把特殊的
$
字符给转义掉呢?
- 答案是否定的, 不过幸运的是,我们可以绕过这个限制,比如通过不支持“变量插值”的模块配置指令专门构造出取值为 $ 的 Nginx 变量,然后再在 echo 中使用这个变量
1 2 3 4 5 6 7 8 9 10 11 12
| geo $dollar { default "$"; }
server { listen 8080;
location /test { echo "This is a dollar sign: $dollar"; } }
|
- 在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如:
1 2 3 4 5 6 7 8
| server { listen 8080;
location /test { set $first "hello "; echo "${first}world"; } }
|
- 变量创建和加载
- Nginx 变量的创建和赋值操作发生在全然不同的时间阶段。
- Nginx 变量的创建只能发生在 Nginx 配置加载的时候
- 而赋值操作则只会发生在请求实际处理的时候。
- 这意味着不创建而直接使用变量会导致启动失败。
- 无法在请求处理时动态地创建新的 Nginx 变量。
- Nginx 变量一旦创建可见范围就是整个Nginx配置,跨越不同虚拟主机的 server 配置块。
- 内部跳转
使用第三方模块 ngx_echo 提供的 echo_exec 配置指令,发起到 location /bar 的“内部跳转”。所谓“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。不同于 301 和 302 会发生二次请求。 exec类似于linux中的exec 请求发出后不会在回到原理的location,而是直接接管。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| server { listen 8080;
location /foo { set $a hello; echo_exec /bar; }
location /bar { echo "a = [$a]"; } }
server { listen 8080;
location /foo { set $a hello; rewrite ^ /bar; }
location /bar { echo "a = [$a]"; } }
|
- 内置变量获取request参数
- 取 arg 值的
$arg_XXX
- 取 cookie 值的
$cookie_XXX
- 取请求头的
$http_XXX
- 取响应头的
$sent_http_XXX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| location /test { echo "name: $arg_name"; echo "class: $arg_class"; }
$ curl 'http://localhost:8080/test' name: class:
$ curl 'http://localhost:8080/test?name=Tom&class=3' name: Tom class: 3
$ curl 'http://localhost:8080/test?name=hello%20world&class=9' name: hello%20world class: 9
###Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式
$ curl 'http://localhost:8080/test?NAME=Marry' name: Marry class:
$ curl 'http://localhost:8080/test?Name=Jimmy' name: Jimmy class:
|
%XX
字符解码
- 可以使用第三方 ngx_set_misc 模块提供的 set_unescape_uri 配置指令:
1 2 3 4 5 6 7 8 9 10 11 12
| location /test { set_unescape_uri $name $arg_name; set_unescape_uri $class $arg_class;
echo "name: $name"; echo "class: $class"; } 现在我们再看一下效果:
$ curl 'http://localhost:8080/test?name=hello%20world&class=9' name: hello world class: 9
|
- 内建变量都是只读的,如
$uri
和 $request_uri
. 应当避免对只读变量进行赋值。
1 2 3 4 5 6 7
| location /bad { set $uri /blah; echo $uri; }
Nginx 在启动的时候报出错误: [emerg] the duplicate "uri" variable in ...
|
- 多个同名arg变量取值
- $arg_XXX 变量在请求 URL 中有多个同名 XXX 参数时,就只会返回最先出现的那个 XXX 参数的值,而默默忽略掉其他实例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| location /test { content_by_lua ' if ngx.var.arg_name == nil then ngx.say("name: missing") else ngx.say("name: [", ngx.var.arg_name, "]") end '; }
$ curl 'http://localhost:8080/test?name=Tom&name=Jim&name=Bob' name: [Tom] 要解决这些局限,可以直接在 Lua 代码中使用 ngx_lua 模块提供的 ngx.req.get_uri_args 函数。
|