1. 前情提要
无论是开发者还是用户,我们在使用某些服务的时候会发现,服务器会获取我们的IP地址,之后通过IP地址为我们提供一些服务,如:根据IP地址定位我们所在的城市,根据IP地址判断我们是否是黑名单用户等等。那么,服务器是如何获取我们的IP地址的呢?我将从java,python,php,nodejs四个后端语言来探讨这个问题。
2. 分析原理 & 代码实现
2.1 分析原理
在网站开发中用户和服务器之间通过http协议进行通信。但是有时候为了加快网站访问速度,站主可能会采用CDN的形式加载。这里我们就涉及到两种获取ip的方式:REMOTE_ADDR和HTTP_X_FORWARDED_FOR。当然还包括HTTP_CLIENT_IP、HTTP_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 {
public String getIp(HttpServletRequest request) { String xForwardedFor = request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.trim().isEmpty()) { String[] ipArr = xForwardedFor.split(","); return ipArr[0].trim(); }
String xRealIp = request.getHeader("X-Real-IP"); if (xRealIp != null && !xRealIp.trim().isEmpty()) { return xRealIp.trim(); }
String remoteAddr = request.getRemoteAddr(); 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): x_forwarded_for = request.headers.get("X-Forwarded-For") if x_forwarded_for: ip_list = x_forwarded_for.split(",") return ip_list[0].strip() x_real_ip = request.headers.get("X-Real-IP") if x_real_ip: return x_real_ip.strip() 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): 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() x_real_ip = request.META.get("HTTP_X_REAL_IP") if x_real_ip: return x_real_ip.strip() 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
|
function getIp(req) { const xForwardedFor = req.headers['x-forwarded-for']; if (xForwardedFor) { const ipList = xForwardedFor.split(','); return ipList[0].trim(); }
const xRealIp = req.headers['x-real-ip']; if (xRealIp) { return xRealIp.trim(); }
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 样图
