获取客户端(用户)真实IP
https://dirask.com/posts/Spring-Boot-get-client-IP-address-from-request-HttpServletRequest-pBv9Bp
两种情况:
- 服务器IP暴露,客户端通过IP直接访问服务器;
- 服务器前面有一层或多层反向代理,客户端通过代理访问服务器。
对于第一种情况,使用request.getRemoteAddr()
可以直接获得客户端IP。不过不常用。
因为目前流行的架构中,基本上服务器不会直接把自己的IP暴露出去。
一些代理软件用的标头
代理软件 |
使用默认HeaderName |
Apache |
Proxy-Client-IP |
Weblogic |
WL-Proxy-Client-IP |
有些代理服务器 |
HTTP_CLIENT_IP |
Nginx |
X-Real-IP |
有些网络可以通过多层代理,那么获得到的IP就会有多个,一般用“,”分割开来。
测试从代理获得的标头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RestController public class HelloController { @GetMapping("/") public String hello(HttpServletRequest request){ System.out.println("\n<br>通过request.getRemoteAddr()获得IP:" + request.getRemoteAddr()); System.out.println("\n<br>通过request.getRemoteHost()获得IP:" + request.getRemoteHost());
Enumeration<String> headerNames = request.getHeaderNames(); System.out.println(("\nHeader List:")); String headerName; while (headerNames.hasMoreElements()){ headerName = headerNames.nextElement(); System.out.println("\n" + headerName + ": " + request.getHeader(headerName)); } return "Hello"; } }
|
1 2 3 4 5 6 7 8 9
| <br>通过request.getRemoteAddr()获得IP:127.0.0.1 <br>通过request.getRemoteHost()获得IP:127.0.0.1 Header List: host: 192.168.227.1 x-real-ip: 127.0.0.1 x-forwarded-for: 192.168.227.129, 127.0.0.1, 127.0.0.1, 127.0.0.1 connection: close user-agent: curl/7.81.0 accept: */*
|
图中可以了解,x-forwarded-for存放了转发过程中的所有IP。
获取用户真实IP
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
| @GetMapping("/ip") public String getIp(HttpServletRequest request){ String[] IP_HEADERS = { "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED", "HTTP_X_CLUSTER_CLIENT_IP", "HTTP_CLIENT_IP", "HTTP_FORWARDED_FOR", "HTTP_FORWARDED", "HTTP_VIA", "REMOTE_ADDR" }; for (String header : IP_HEADERS){ String value = request.getHeader(header); if (value == null || StringUtils.isEmpty(value)){ continue; } String part = value.split(",")[0]; return part; } return request.getRemoteAddr(); }
|
![image]()
equalsIgnoreCase()
将字符串与指定的对象比较,忽略大小写。