惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
腾讯CDC
Engineering at Meta
Engineering at Meta
The Cloudflare Blog
T
The Blog of Author Tim Ferriss
S
SegmentFault 最新的问题
J
Java Code Geeks
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
美团技术团队
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Announcements
Recent Announcements
Vercel News
Vercel News
V
Visual Studio Blog
博客园 - 叶小钗
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学

PixelNest

会议是效率的杀手 国庆出游记录 对居家办公的一些想法 2022 春节 《搏击俱乐部》的结局 纪念 PAI 头一回达到 100 卡片笔记法 《刑法学讲义》的部分摘录 迁移博客 《UNIX 传奇》摘录 就地过年 一点记录:docker-compose 编排不同项目间的网络 近期读的几本书 办新身份证 git 获取其他分支的单个文件或目录 我的高考成绩 推荐 2020 年上半年的 8 部影视作品 ChromeOS 开发者模式 终于下单了《守望者》 联通来电管家服务 一些实用的 bash 代码片段 关于 鸟枪换炮 《架构整洁之道》摘录 惨淡的星球大战 旧笔记本电脑 if...then... 命令行检测 SSL 证书过期时间 《程序员的职业素养》读书笔记 2019 国庆假期
Koa 获取客户端 IP
2019-03-20 · via PixelNest

这篇文章记录在 Koa 应用里获取真实客户端 IP 的方法、X-Forwarded-For 等 HTTP 头部字段的含义,以及相关的 Nginx 配置。

ctx.request.ip

在 Koa 里获取客户端 IP 非常容易,简单来说,ctx.request.ip 就是客户端 IP。哪个 IP 请求过来的,哪个 IP 就是客户端 IP。

但是在生产环境服务器上,Koa 的前端往往还有一个反向代理服务器,比如 Nginx。这时候 ctx.request.ip 的值就是 Nginx 所在的 IP,往往就是本地地址 127.0.0.1。那么这时要怎么获取到客户端的真实 IP?

Koa 的文档里对 ctx.request.ip 的描述是这样的:

Request remote address. Supports X-Forwarded-For when app.proxy is true.

这句文档的后半句针对的就是上面提到的问题,也指明了方向。

下面是答案,做两件事情就可以了 :

  1. 在 Nginx 反向代理配置 proxy_pass 的部分添加这样一行。 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  2. 在 Koa 应用里设置 app.proxytrue

这样,从 ctx.request.ip 拿到的就是客户端的真实 IP,而不是(反向)代理的 IP。

Nginx 通过设置 X-Forwarded-For 告诉 Koa 它为谁做代理。如果 Koa 中没有配置 app.proxy = true,Koa 会忽略 Nginx 在 HTTP 请求头部添加的 X-Forwarded-For 字段,所以要设置app.proxytrue

X-Forwarded-For

可以从 X-Forwarded-For 的名称里猜到,这个 HTTP 请求头部字段的含义是告诉 HTTP 的请求接收方「我在转发的谁的请求」,它并不只是包含最原始的客户端 IP,在维基百科的描述如下:

这一HTTP头一般格式如下:

X-Forwarded-For: client1, proxy1, proxy2

其中的值通过一个 逗号+空格 把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。请求由client1发出,到达了proxy3(proxy3可能是请求的终点)。请求刚从client1中发出时,XFF是空的,请求被发往proxy1;通过proxy1的时候,client1被添加到XFF中,之后请求被发往proxy2;通过proxy2的时候,proxy1被添加到XFF中,之后请求被发往proxy3;通过proxy3时,proxy2被添加到XFF中,之后请求的的去向不明,如果proxy3不是请求终点,请求会被继续转发。

实际的生产环境中,极有可能并不是用户(客户端)-> 服务器 Nginx -> 服务器 Koa 这样简单的三个点,在用户和服务器之前,可能还有其他代理,比如 CDN,负载均衡,或许还有用户自己用的代理服务。通过上述方法,还是可以拿到最原始的真实客户端 IP,当然,这需要整个请求链条上各个点都遵照 X-Forwarded-For 头部的用法。

每个点把请求代理给下一个点时,都需要带上 X-Forwarded-For 头部字段,具体的做法是要把收到请求中的 X-Forwarded-For 拿过来,再给这个字段追加发起这个请求的节点 IP。

上面提到的 Nginx 配置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 就是这么做的,在 Nginx 文档里有对 $proxy_add_x_forwarded_for 这个变量的说明:

$proxy_add_x_forwarded_for

the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.

$proxy_add_x_forwarded_for 是指请求过来的 HTTP 中 X-Forwarded-For 头部再追加上请求方自身的 IP($remote_addr)。

如果 Nginx 收到的请求中的 X-Forwarded-For 是空的,有可能这个 Nginx 是最靠近真实用户的节点,也有可能是前一节代理节点丢掉了 X-Forwarded-For 字段,这时 Nginx 转发请求时添加的 X-Forwarded-For 就是 $remote_addr 变量,即请求发起方的 IP。

ctx.request.ips

再回到 Koa。当 Koa 收到的请求中 X-Forwarded-For 包含多个 IP 时,也就是 X-Forwarded-For: client1, proxy1, proxy2 这样的形式,可以通过 ctx.request.ips 获取到这个 IP 列表,值为 [client1, proxy1, proxy2],ctx.request.ips[0]是真实客户端 IP(与ctx.request.ip是同一个 IP,即client1`),数组后面的各个 IP 是各级代理的 IP 地址。