XVIT

Jun 16, 2026

后端获取客户端公网IP

1. 前情提要

无论是开发者还是用户,我们在使用某些服务的时候会发现,服务器会获取我们的IP地址,之后通过IP地址为我们提供一些服务,如:根据IP地址定位我们所在的城市,根据IP地址判断我们是否是黑名单用户等等。那么,服务器是如何获取我们的IP地址的呢?我将从javapythonphpnodejs四个后端语言来探讨这个问题。

2. 分析原理 & 代码实现

2.1 分析原理

在网站开发中用户和服务器之间通过http协议进行通信。但是有时候为了加快网站访问速度,站主可能会采用CDN的形式加载。这里我们就涉及到两种获取ip的方式:REMOTE_ADDRHTTP_X_FORWARDED_FOR。当然还包括HTTP_CLIENT_IPHTTP_X_REAL_IP等,获取的方式都一样,这里就不一一列举了。

2.2 代码实现

这里需要说明一下啥时候需要获取REMOTE_ADDR,啥时候获取HTTP_X_FORWARDED_FOR。如果我们服务器使用了Nginx或者Apache等反向代理服务器,或者其他CDN加速服务,那么我们需要获取HTTP_X_FORWARDED_FOR,否则我们获取REMOTE_ADDR即可。

2.2.1 java代码实现:

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
28
29
30
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;

@Component
public class IpUtil {

/**
* @param request 请求对象
* @return 客户端真实IP
*/
public String getIp(HttpServletRequest request) {
// 1. 优先取 X-Forwarded-For
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.trim().isEmpty()) {
String[] ipArr = xForwardedFor.split(",");
return ipArr[0].trim();
}

// 2. 其次 X-Real-IP
String xRealIp = request.getHeader("X-Real-IP");
if (xRealIp != null && !xRealIp.trim().isEmpty()) {
return xRealIp.trim();
}

// 3. 兜底原始远程地址
String remoteAddr = request.getRemoteAddr();
// 本地IPv6 ::1 替换为 127.0.0.1
return "::1".equals(remoteAddr) ? "127.0.0.1" : remoteAddr;
}
}

2.2.2 python代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_ip(request):
# 1. X-Forwarded-For
x_forwarded_for = request.headers.get("X-Forwarded-For")
if x_forwarded_for:
ip_list = x_forwarded_for.split(",")
return ip_list[0].strip()
# 2. X-Real-IP
x_real_ip = request.headers.get("X-Real-IP")
if x_real_ip:
return x_real_ip.strip()
# 3. 兜底远程地址
remote_ip = request.remote_addr
return "127.0.0.1" if remote_ip == "::1" else remote_ip

上面那个是flask版本的,下面这个是Django版本

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_ip(request):
# 1. X-Forwarded-For
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for:
ip_list = x_forwarded_for.split(",")
return ip_list[0].strip()
# 2. X-Real-IP
x_real_ip = request.META.get("HTTP_X_REAL_IP")
if x_real_ip:
return x_real_ip.strip()
# 3. 兜底远程地址
remote_ip = request.META.get("REMOTE_ADDR")
return "127.0.0.1" if remote_ip == "::1" else remote_ip

2.2.3 php代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function get_ip() {
if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$ip_list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
return trim($ip_list[0]);
}

if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER['HTTP_X_REAL_IP'];
}

// 无代理直连兜底
$ip = $_SERVER['REMOTE_ADDR'];
return $ip === '::1' ? '127.0.0.1' : $ip;
}

2.2.4 nodejs代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 获取客户端真实IP
* @param {import('express').Request} req express请求对象
* @returns {string} ip地址
*/
function getIp(req) {
// 1. X-Forwarded-For
const xForwardedFor = req.headers['x-forwarded-for'];
if (xForwardedFor) {
const ipList = xForwardedFor.split(',');
return ipList[0].trim();
}

// 2. X-Real-IP
const xRealIp = req.headers['x-real-ip'];
if (xRealIp) {
return xRealIp.trim();
}

// 3. 兜底远程地址
let remoteIp = req.socket.remoteAddress;
return remoteIp === '::1' ? '127.0.0.1' : remoteIp;
}

3. 总结 & 样图

3.1 总结

服务器获取用户公网IP的方法其实很简单,主要是因为http的协议,他在提交客户端数据的时候在请求头里面会携带Remote-Addr的参数,这个就是客户端的公网IP(客户方运营商的IP),但是我们也说过如果使用了Nginx或者其他的CDN加速的话我们还需要配置X-Forwarded-For来获取。原因就是CDN和Nginx是代理,虽然他也可以获取到客户端的IP但是这两个东西和我们后端代码是在同一个服务器,这样的话后端代码获取到的IP地址就是服务器本地的地址(127.0.0.1或localhost),所以我们必须要再加一层X-Forwarded-For来获取客户端的公网IP。当然现在的代码仅限于学习参考,实际开发中还需要考虑很多其他因素,如:请求频率限制、请求权限、IP黑名单等等。

3.2 样图

后端获取客户端公网IP

OLDER > < NEWER