我正在开发一个 Django 项目,用户将根据他们的位置获得自定义信息。为了做到这一点,我使用他们的 IP 地址来识别他们的国家。为了使数据库中的数据保持一致,我需要确保我有一个准确的 IP。
我了解使用 META 通常使用客户端浏览器发送的标头,但我不知道这是否适用于该REMOTE_ADDR
属性。
TLDR:HttpRequest.get_host()
和 和有什么不一样HttpRequest.META['REMOTE_ADDR']
?
我正在开发一个 Django 项目,用户将根据他们的位置获得自定义信息。为了做到这一点,我使用他们的 IP 地址来识别他们的国家。为了使数据库中的数据保持一致,我需要确保我有一个准确的 IP。
我了解使用 META 通常使用客户端浏览器发送的标头,但我不知道这是否适用于该REMOTE_ADDR
属性。
TLDR:HttpRequest.get_host()
和 和有什么不一样HttpRequest.META['REMOTE_ADDR']
?
HttpRequest.get_host()
和之间的区别在于HttpRequest.META['REMOTE_ADDR']
,第一个检查以下标头中的 IP 以降低优先级:
HTTP_X_FORWARDED_HOST
HTTP_HOST
SERVER_NAME combined with SERVER_PORT
而第二个检查标头中的 IP REMOTE_ADDR
。
返回的信息类型存在巨大差异:get_host()
将为您提供托管应用程序的服务器的名称,而不是客户端的 IP。
更详细地说,这里是实现get_host()
:
def get_host(self):
"""Returns the HTTP host using the environment or request headers."""
# We try three options, in order of decreasing preference.
if settings.USE_X_FORWARDED_HOST and (
'HTTP_X_FORWARDED_HOST' in self.META):
host = self.META['HTTP_X_FORWARDED_HOST']
elif 'HTTP_HOST' in self.META:
host = self.META['HTTP_HOST']
else:
# Reconstruct the host using the algorithm from PEP 333.
host = self.META['SERVER_NAME']
server_port = str(self.META['SERVER_PORT'])
if server_port != ('443' if self.is_secure() else '80'):
host = '%s:%s' % (host, server_port)
allowed_hosts = ['*'] if settings.DEBUG else settings.ALLOWED_HOSTS
domain, port = split_domain_port(host)
if domain and validate_host(domain, allowed_hosts):
return host
else:
msg = "Invalid HTTP_HOST header: %r." % host
if domain:
msg += "You may need to add %r to ALLOWED_HOSTS." % domain
raise DisallowedHost(msg)
如果您想检查客户端 IP 地址,这里有一些值得检查的标头(请参阅获取客户端 IP 地址:REMOTE_ADDR、HTTP_X_FORWARDED_FOR,还有什么有用的?):
REMOTE_ADDR
HTTP_X_FORWARDED_FOR
HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
可以是逗号分隔的 IP 列表HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
如果您不知道选择哪一个(如果不是全部),您可以记录这些标题并随着时间的推移务实地添加新的检查。