在Django Views中获取客户端真实IP,仅拿到127.0.0.1如何解决?
Django提取客户端真实IP的其他实现方式
你拿到的IP始终是127.0.0.1,是因为Django服务前端部署了反向代理(如Nginx、CDN、负载均衡),请求由代理转发到Django,所以REMOTE_ADDR默认获取的是代理服务器的本地地址。
下面是除你给出的基础X-Forwarded-For提取逻辑之外的其他实现方案:
方案1:使用Django内置中间件
Django 3.1及以上版本内置了XForwardedForMiddleware,无需自行编写IP提取逻辑,只需修改settings.py配置即可:
- 把
django.middleware.http.XForwardedForMiddleware添加到MIDDLEWARE列表的最顶部 - 新增配置:
USE_X_FORWARDED_HOST = True # 开启HTTPS的场景需要额外加下面的配置 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # 把你的反向代理服务器IP添加到允许列表,避免安全风险 ALLOWED_HOSTS = ['你的域名', '代理服务器IP']
配置完成后直接调用request.META.get('REMOTE_ADDR')就能获取到真实客户端IP。
方案2:兼容多代理头的自定义逻辑
不同反向代理、CDN厂商会使用自定义的IP请求头,你可以按优先级判断多个常用头,覆盖更多部署场景:
def get_client_ip(request): # 按优先级排序的真实IP请求头列表 IP_HEADERS = [ 'HTTP_X_REAL_IP', # Nginx反向代理常用头 'HTTP_CF_CONNECTING_IP', # Cloudflare CDN专用头 'HTTP_X_FORWARDED_FOR', 'HTTP_X_CLUSTER_CLIENT_IP', # 集群负载均衡常用头 'HTTP_X_FORWARDED' ] for header in IP_HEADERS: ip_val = request.META.get(header) if not ip_val: continue # 处理多IP逗号分隔的场景,取第一个为真实客户端IP if ',' in ip_val: ip = ip_val.split(',')[0].strip() else: ip = ip_val.strip() return ip # 兜底逻辑 return request.META.get('REMOTE_ADDR')
注意:你原有逻辑里取
split(',')[-1]是错误的,X-Forwarded-For的格式为客户端真实IP, 第一层代理IP, 第二层代理IP...,取最后一位会拿到离Django最近的代理IP而非客户端IP。
方案3:使用成熟第三方包
直接用经过社区验证的第三方包处理IP提取逻辑,自带合法性校验、伪造IP过滤能力,比自行编写的逻辑更安全,比如django-ipware:
- 安装包:
pip install django-ipware - 调用示例:
from ipware import get_client_ip def your_view(request): client_ip, is_public_ip = get_client_ip(request) # client_ip为提取到的客户端IP,is_public_ip表示该IP是否为公网可路由地址
安全注意事项
所有基于转发头提取IP的方案,都要在反向代理层配置:丢弃用户请求中携带的对应IP头,仅允许信任的代理服务器添加/修改这些头,避免攻击者伪造头信息提交假IP。
内容的提问来源于stack exchange,提问作者aakarsh2126
相关产品推荐
相关产品推荐

