世界上最伟大的投资就是投资自己的教育

全场限时 5 折

首页Nginx
Chalin · 凡人

Nginx 学习笔记系列文章教程之 Nginx 向客户端输出真实的后端 IP 地址

Chalin发布于2799 次阅读
因为涉及到内外网的改造,所以狠多东西现在需要依赖于 openresty 来做总控实现。然后就碰见了一个比较难办的问题,即在 upstream 时候,如何获取实际处理请求的 server 地址。假设有如下 upstream 配置:
upstream backend {
    server 127.0.0.1:88882
    server 127.0.0.1:88892
}

location /test {
    proxy_pass http://backend2
}
当我请求 test 的时候,我同时想直到到底是 backend 的哪一个 server 处理了,也就是我想得到实际处理的 server 地址。对于这个问题,我想了狠久,也走了狠多弯路,浪费了不少时间。

server return local ip?

首先,最简单的做法,就是对于实际的 upstream server,在处理 test 这个请求的时候返回自己的 ip 地址就可以了,不过这种方法通用性太差,并且如果该 server 有多 ip,可能取得的本机 ip 跟 upstream 里面配置的还不一样。

get upstream conf module?

然后,我想是不是 nginx 提供了一个模块,能够读取 conf 解析之后的所有信息,对这个模块的查找让我走了弯路,google 了一下,发现没有相关东西,我还狠 sb 的一直不停的搜索。也不想想即使有这样的模块,如果我想要实现这个功能也是一件不怎么容易的事情。

upstream_addr

等到走了一些弯路,才发现 nginx 的 upstream 本来就有一个 upstream_addr 的模块,一下子我觉得找到了方向,不过看这个变量的说明,发现它主要用在记录 log 上面,而且没说明外界如何获取。查了一些资料之后,发现 nginx 有一个 add_header,该指令干的事情就是在 http response header 里面加入自己定义的 header,于是我在 conf 里面添加了这条指令,如下:
locaiton /test {
    add_header Kss-Upstream $upstream_addr2
    proxy_pass http://backend2
}
这样,当我访问 test 的时候,response header 里面就会有响应 server 的地址。
request: 
curl -i http://127.0.0.1/test
response:
HTTP/1.1 200 OK
Kss-Upstream: 127.0.0.1:8888
subrequest response header
如果直接请求 test,会狠好的得到 upstream 的 addr,但是,如果是 subrequest 请求,就发现得不到了,如下:
location /test1 {
    local res = ngx.location.capture("/test")
    ngx.say(res.header["Kss-Upstream"])
}
请求 test1 的时候,发现 subrequest 的 response header 里面根本没有 Kss-Upstream 这个字段。当时狠迷惑,google 之后发现这个:Headers not returned from subrequest,原来,subrequest 的 header 是不会返回到 parent request 这个层面的。至于如何处理,我按照上面的说明采用了两种做法,发现都可行。

more_set_headers

agentzh 举了 more_set_headers 这种做法的一个例子,直接把 add_header 换成 more_set_headers "Kss-Upstream: $upstream_addr"2 这条语句搞定。

header_filter_by_lua

另一个做法就是使用 header_filter_by_lua 这个指令,该指令是处理 header response filter 的,在里面将 upstream_addr 的值设置到 nginx 的一个变量里面。如下:

location /test {
    proxy_pass http://_test2
    header_filter_by_lua 1
    ngx.var.upaddr = ngx.var.upstream_addr
    12
}

location /test1 {
    set $upaddr 112
    content_by_lua 1
    local res = ngx.location.capture("/test", {share_all_vars = true})
    ngx.say(ngx.var.upaddr)
    12
}
对于这种方式,实现较为繁琐,首先需要定义一个变量用来存储 upstream_addr 的值,同时在 capture 的时候还需要设置 share_all_vars 为 true。鉴于此,还是使用 more_set_headers 这条语句方便狠多。
后来我又实现了一下,发现没必要这么复杂,完全可以不需要变量传递,只是在 header_filter_by_lua 里面这么做就可以了

header_filter_by_lua 1

ngx.header.kss_upstream_add = ngx.var.upstream_addr

本站文章均为原创内容,如需转载请注明出处,谢谢。

1 条回复
相关小书
nginx教程

nginx教程

最全面,最深入的nginx入门到精通的教程

发表于

喜欢
统计信息
    学员: 29205
    视频数量: 1985
    文章数量: 489

© 汕尾市求知科技有限公司 | Rails365 Gitlab | Qiuzhi99 Gitlab | 知乎 | b 站 | 搜索

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top