求助大佬们, docker 内的 springboot 项目如何获取 http 请求的真实 ip?

2021-11-26 09:19:03 +08:00
 Aliberter

现有代码如下:

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

目前测试服务器,没有 Nginx ,没有域名解析,直接请求服务器的 ip+端口的,实际最后都是走到 ip = request.getRemoteAddr(),然后取到的是 172 开头的 docker 内网 ip ,试了试--net=host 也不管用,访问不通了就,不太懂 docker 网络这块,求助大佬们。

2379 次点击
所在节点    Docker
14 条回复
Aliberter
2021-11-26 09:30:41 +08:00
我看百度上,大部分都是在外边加一层 nginx ,提前配置好代码里这些请求头啥的,然后后面走到代码里也就能直接取取来请求头的值,就是用户的真实 ip 了,不知道是否可行~
hopingtop
2021-11-26 09:46:36 +08:00
remoteAddr 是真正连接你服务端的 IP ,但是往往一次网络请求可能会经过几层网络代理,那么你渠道的 IP 就是最后一层代理,并不是真的 ClientIP 。
因为 Docker 他有网络模式,默认情况下( bridge )所以他其实就是相当于一层代理了。
hopingtop
2021-11-26 09:47:54 +08:00
@hopingtop 但是 HOST 网络模式应该和宿主机共享 Namespace ,如果中间没有其他代理,按理能取到 IP
hopingtop
2021-11-26 09:48:53 +08:00
@hopingtop ..... 按了几次 CTRL 回车,导致就没有回答完。。。狗头。。。

Docker 使用了 Linux 的 Namespaces 技术来进行资源隔离,如 PID Namespace 隔离进程,Mount Namespace 隔离文件系统,Network Namespace 隔离网络等。一个 Network Namespace 提供了一份独立的网络环境,包括网卡、路由、Iptable 规则等都与其他的 Network Namespace 隔离。

host 模式类似于 Vmware 的桥接模式,与宿主机在同一个网络中,但没有独立 IP 地址。一个 Docker 容器一般会分配一个独立的 Network Namespace 。但如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace ,而是和宿主机共用一个 Network Namespace 。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。
wolfie
2021-11-26 09:54:05 +08:00
一般都从 x-forwarded-for 拿,多个网关会包含多个 ip ,逗号分隔。
也有 x-real-ip 的情况。
rationa1cuzz
2021-11-26 10:06:21 +08:00
--net=host 按道理应该使用宿主机的 ip 端口,访问不通是不是端口被占用了?
Aliberter
2021-11-26 10:09:13 +08:00
@hopingtop 多谢大佬,我拜读一下
Aliberter
2021-11-26 10:10:51 +08:00
@rationa1cuzz 对,解决了,--net=host 确实管用,我重新给防火墙开了这个端口才通了,但是有个疑问就是,之前一直用端口映射的时候,我记得我加过防火墙,而且也一直是通的,能用的,改成这个模式后,又加了一遍才通,真搞不懂。
xueyuanh
2021-11-26 10:48:59 +08:00
@rationa1cuzz 用了--net=host 容器是不是就会把机器的 80 端口给占用了,之前用 docker 启一个 nginx ,一直占用 80 端口,但是 nginx 的默认监听端口已经被我换成别的了,最后去掉--net=host 才正常
rationa1cuzz
2021-11-26 11:15:27 +08:00
@xueyuanh 是的,你可以 lsof 或者 netstat 看一下就知道了,你可以看看这个 https://docs.docker.com/network/
pixiaotiao
2021-11-26 12:16:23 +08:00
一层一层传过来
yangyaofei
2021-11-26 12:16:55 +08:00
不知道这个可以不可以, 当时 https nginx 转发的时候也会遇到这个问题, 加这个配置解决的:

```yaml
server:
port: 8080
address: 0.0.0.0
# Enable HTTPS When Running behind a Proxy Server
# https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.security.enable-https
tomcat:
remoteip:
remote-ip-header: "x-forwarded-for"
protocol-header: "x-forwarded-proto"

```
yangyaofei
2021-11-26 12:18:39 +08:00
```
server:
port: 8080
address: 0.0.0.0
# Enable HTTPS When Running behind a Proxy Server
tomcat:
remoteip:
remote-ip-header: "x-forwarded-for"
protocol-header: "x-forwarded-proto"

```
yangyaofei
2021-11-26 12:19:02 +08:00
这个 markdown 不好用啊 😂😂😂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/818060

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX