欢迎访问陈同学博客原文
使用 Nginx 基于客户端IP进行限流时,需在代理中拿到客户端真实IP。获取IP方式有多种,如利用 remote_addr、X-Real-IP、X-Forwarded-For等。
以前看到一些项目通过获取 X-Forwarded-For 中首个IP作为真实IP,这其实有些不妥之处。本文记录下在 Nginx 作反向代理时, X-Forwarded-For 及其他获取真实IP的相关内容。
关于 X-Forwarded-For
X-Forwarded-For 是一个HTTP拓展头,起初在 RFC2616 (HTTP/1.1) 中并未定义,但后来被广泛用于表示客户端真实IP。而后 RFC7239 (Forwarded HTTP Extension) 中又提供了标准的 Forwarded 头,使用 X-Forwarded-For 来提取真实IP也就成了事实上的标准。
X-Forwarded-For 存储了客户端IP以及请求链路上各代理IP,假设请求依次通过 proxy1、proxy2 后抵达服务,那 X-Forwarded-For 的值为:客户端IP, proxy1 IP, proxy2 IP,IP之间以逗号隔开。
X-Forwarded-For 首个IP一定真实吗?
当使用 nginx 做反向代理时,通过 HttpServletRequest 的 getRemoteAddr() 得到的是最后一个代理所在机器的IP,而非客户端的真实IP。先通过下面一些例子演示下 $remote_addr 和 X-Forwarded-For 的情况。
请求 -> proxy1 -> proxy2 -> proxy3 -> 后端服务(/hello)
proxy1、2、3在同一台机器(仅作测试)。
使用 $remote_addr
内置变量参考 ngx_http_core_module 中 Embedded Variables 部分。
$remote_addr 表示客户端的IP。
为了方便,为proxy1、2、3 设置如下日志格式:
log_format proxy1 '"[proxy1]" $remote_addr "$request" $status';
log_format proxy2 '"[proxy2]" $remote_addr "$request" $status';
log_format proxy3 '"[proxy3]" $remote_addr "$request" $status';
访问后,日志如下: