Django获取请求IP的正确方法和最佳实践

 更新时间:2026年05月26日 16:56:52   作者:detayun  
这篇文章主要为大家详细介绍了Django获取客户端IP的正确方法总结以及常见错误和解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

最近在项目中遇到一个诡异的问题:使用域名访问能获取到真实IP,但用IP+端口访问时,获取到的却是 127.0.0.1。经过一番折腾,终于搞清楚了原因。今天就来总结一下 Django获取客户端IP的正确姿势

常见的错误写法

很多同学(包括我自己)一开始会这样写:

# ❌ 错误:'IP' 不是Django的标准META key
ip = request.META['IP']  # KeyError!

# ❌ 错误:只用REMOTE_ADDR,代理时会出错
ip = request.META['REMOTE_ADDR']  # 代理时返回127.0.0.1

踩坑现场

  • 直连服务器:✅ 能获取到真实IP
  • Nginx反向代理:❌ 返回 127.0.0.1
  • CDN/WAF:❌ 返回CDN的IP,不是用户真实IP

Django的META中有哪些IP相关的Key?

META Key说明直连代理CDN优先级
REMOTE_ADDR直连的客户端IP✅ 真实IP❌ 代理IP(127.0.0.1)❌ 最后一跳IP⭐⭐
HTTP_X_FORWARDED_FOR代理链中的真实IP❌ 无✅ 真实IP✅ 真实IP⭐⭐⭐⭐
HTTP_X_REAL_IPNginx传递的真实IP❌ 无✅ 真实IP⭐⭐⭐
HTTP_CLIENT_IP备用方案❌ 无⭐⭐

优先级

HTTP_X_FORWARDED_FOR > HTTP_X_REAL_IP > REMOTE_ADDR

最佳实践:通用获取IP函数

方法1:标准写法(推荐)⭐⭐⭐

def get_client_ip(request):
    """
    获取客户端真实IP(支持直连、代理、CDN)
    
    Args:
        request: Django的HttpRequest对象
    
    Returns:
        str: 客户端真实IP
    """
    # 1. 优先从 HTTP_X_FORWARDED_FOR 获取(代理传递的真实IP)
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        # 可能有多个IP(如:client, proxy1, proxy2),取第一个
        ip = x_forwarded_for.split(',')[0].strip()
    else:
        # 2. 没有代理,直接用 REMOTE_ADDR
        ip = request.META.get('REMOTE_ADDR', '127.0.0.1')
    
    # 3. 过滤内网IP(可选,防止伪造)
    if ip.startswith('127.') or ip.startswith('192.168.'):
        return '0.0.0.0'
    
    return ip

使用示例

def my_view(request):
    ip = get_client_ip(request)
    print(f"客户端IP: {ip}")  # 输出:123.45.67.89
    return JsonResponse({'ip': ip})

方法2:更严谨的写法(防伪造)⭐⭐⭐⭐

def get_client_ip(request):
    """
    获取客户端真实IP(防伪造、支持多层代理)
    """
    # 尝试多个可能的IP来源(按优先级排序)
    ip_keys = [
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_REAL_IP',
        'HTTP_CLIENT_IP',
        'REMOTE_ADDR',
    ]
    
    for key in ip_keys:
        ip = request.META.get(key)
        if ip:
            # HTTP_X_FORWARDED_FOR 可能有多个IP,取第一个
            if key == 'HTTP_X_FORWARDED_FOR':
                ip = ip.split(',')[0].strip()
            
            # 过滤内网IP和无效IP
            if ip and not ip.startswith(('127.', '192.168.', '0.')):
                return ip
    
    return '0.0.0.0'

方法3:使用中间件(全局生效)⭐⭐⭐⭐⭐

如果你想在所有视图中都能用 request.client_ip,可以写个中间件:

# middleware.py
class ClientIPMiddleware:
    """
    中间件:自动在request对象上添加client_ip属性
    """
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 获取真实IP
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            request.client_ip = x_forwarded_for.split(',')[0].strip()
        else:
            request.client_ip = request.META.get('REMOTE_ADDR', '127.0.0.1')
        
        response = self.get_response(request)
        return response

配置中间件settings.py):

MIDDLEWARE = [
    # ... 其他中间件
    'myapp.middleware.ClientIPMiddleware',  # ⭐ 添加这行
]

使用

def my_view(request):
    ip = request.client_ip  # ⭐ 直接用,超方便!
    print(f"客户端IP: {ip}")
    return JsonResponse({'ip': ip})

Nginx配置(最优雅的方案)⭐⭐⭐⭐⭐

如果你用Nginx做反向代理,在Nginx层传递真实IP是最优解

server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://127.0.0.1:8000;
        # ⭐⭐⭐ 关键:传递真实IP ⭐⭐⭐
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

然后Django中直接用:

# ✅ 现在REMOTE_ADDR就是真实IP了
ip = request.META.get('REMOTE_ADDR')

不同场景对比

场景直连Nginx代理CDN/WAF推荐方法
REMOTE_ADDR✅ 真实IP❌ 127.0.0.1❌ CDN IP❌ 不推荐
HTTP_X_FORWARDED_FOR❌ 无✅ 真实IP✅ 真实IP⭐⭐⭐⭐
中间件 request.client_ip⭐⭐⭐⭐⭐
Nginx配置⭐⭐⭐⭐⭐

常见坑点

坑1:HTTP_X_FORWARDED_FOR可以伪造!

# 恶意请求(伪造IP)
curl -H "X-Forwarded-For: 8.8.8.8" http://your-server.com

解决方案

  • 只信任自己的Nginx/CDN(配置白名单)
  • 过滤内网IP(127.*, 192.168.*
  • 使用 HTTP_X_REAL_IP(Nginx专属,难以伪造)

坑2:多层代理时,HTTP_X_FORWARDED_FOR有多个IP

用户 → 代理1 → 代理2 → 你的服务器

HTTP_X_FORWARDED_FOR = "用户IP, 代理1IP, 代理2IP"

解决方案

# 取第一个(最左边的是真实IP)
ip = request.META.get('HTTP_X_FORWARDED_FOR').split(',')[0].strip()

坑3:IPv6的IP获取

# IPv6地址示例:2001:0db8:85a3::8a2e:0370:7334
# 同样适用上述方法
ip = get_client_ip(request)  # 支持IPv4和IPv6

完整工具类(直接复制用)

# utils.py
class IPUtils:
    @staticmethod
    def get_client_ip(request):
        """获取客户端真实IP(防伪造、支持代理)"""
        for key in ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR']:
            ip = request.META.get(key)
            if ip:
                if key == 'HTTP_X_FORWARDED_FOR':
                    ip = ip.split(',')[0].strip()
                if ip and not ip.startswith(('127.', '192.168.', '0.')):
                    return ip
        return '0.0.0.0'

# 使用
from myapp.utils import IPUtils
ip = IPUtils.get_client_ip(request)

总结

方法代码推荐度适用场景
request.META['IP']错误别用!
get_client_ip()上面的函数⭐⭐⭐⭐⭐通用推荐
✅ 中间件request.client_ip⭐⭐⭐⭐⭐全局使用
✅ Nginx配置proxy_set_header⭐⭐⭐⭐⭐有Nginx时

最终推荐

# ✅ 最简单:复制这个函数就够了
def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        return x_forwarded_for.split(',')[0].strip()
    return request.META.get('REMOTE_ADDR', '127.0.0.1')

# 使用
ip = get_client_ip(request)

一句话总结:别用 request.META['IP'],用 HTTP_X_FORWARDED_FORREMOTE_ADDR! 🎉

提示:如果你的服务在CDN后面(如Cloudflare),记得在CDN控制台开启"传递真实IP"功能,否则 HTTP_X_FORWARDED_FOR 也会是CDN的IP哦!

到此这篇关于Django获取请求IP的正确方法和最佳实践的文章就介绍到这了,更多相关Django获取请求IP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python 获取项目根路径的代码

    Python 获取项目根路径的代码

    这篇文章主要介绍了Python 获取项目根路径的代码文中通过代码给大家介绍了Python获取当前目录和上级目录,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • 用python画一只可爱的皮卡丘实例

    用python画一只可爱的皮卡丘实例

    今天小编就为大家分享一篇用python画一只可爱的皮卡丘实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • Python数据结构之链表详解

    Python数据结构之链表详解

    在顺序存储方式中,根据数据元素的序号就可随机存取表中任何一个元素,但同时在插入和删除运算需要移动大量的元素,造成算法效率较低。解决此缺陷的一个办法是:对线性表采用链式存储方式。本文将介绍链式存储结构的特点以及各种基本操作的实现。需要的可以参考一下
    2022-01-01
  • python非递归全排列实现方法

    python非递归全排列实现方法

    下面小编就为大家带来一篇python非递归全排列实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Python魔法方法 容器部方法详解

    Python魔法方法 容器部方法详解

    这篇文章主要介绍了Python魔法方法 容器部方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Python中decorator使用实例

    Python中decorator使用实例

    这篇文章主要介绍了Python中decorator使用实例,本文讲解了如何调用decorator、decorator函数的定义、decorator的应用场景等内容,需要的朋友可以参考下
    2015-04-04
  • python实现猜单词小游戏

    python实现猜单词小游戏

    这篇文章主要为大家详细介绍了python实现猜单词小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • 新手该如何学python怎么学好python?

    新手该如何学python怎么学好python?

    怎么学好python?怎么灵活应用python?
    2008-10-10
  • Python随手笔记之标准类型内建函数

    Python随手笔记之标准类型内建函数

    Python提供了一些内建函数用于基本对象类型:cmp(),repr(),str(),type()和等同于repr()的(' ')操作符,本文给大家分享Python随手笔记之标准类型内建函数,对python内建函数相关知识感兴趣的朋友一起学习吧
    2015-12-12
  • python plotly画柱状图代码实例

    python plotly画柱状图代码实例

    这篇文章主要介绍了python plotly画柱状图代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论