Skip to content

社交平台那个IP属地是怎么实现的?拆给你看

从2022年开始,各大社交平台都上线了"IP属地":发帖显示"来自广东",评论显示"来自北京"。这功能看着小,其实背后有一套完整的链路。今天就把它拆开,讲讲要是我来做,我会怎么做。

先搞清楚"属地"到底存的是什么

平台显示的IP属地,通常只精确到省级(或海外国家)。注意,不是实时查,而是发帖/评论的那一刻查一次,然后把结果存下来

这是关键区别:

  • 错误的做法:每次展示帖子都去查一次IP归属地——流量爆炸,纯属浪费。
  • 正确的做法:发帖时查一次归属地,存进数据库,展示的时候直接读。

技术链路拆解

第1步:拿到发布者的IP

用户发帖的请求到服务器,REMOTE_ADDR 就是IP。如果挂了CDN/负载均衡,记得取真实IP头:

python
ip = request.headers.get('X-Forwarded-For', '').split(',')[0].strip() or request.remote_addr

第2步:查归属地

调IP9这类查询接口,拿到省市:

http
GET https://ip9.com.cn/get?ip=58.30.0.0

返回里的 prov 就是省级。

第3步:只存省,不存细粒度

存的时候按平台规则处理:

python
def format_location(data):
    if not data:
        return None
    # 国内显示省,海外显示国家
    if data.get("country") == "中国" and data.get("prov"):
        return data["prov"]
    return data.get("country")

这样既能满足"展示属地"的需求,又不会把用户精确到区县——展示到省,是隐私和体验的平衡点,别做过头。

第4步:入库 + 展示

发帖时把 location 存进帖子记录,展示时直接查字段渲染,不碰接口。

缓存怎么做

虽然每帖只查一次,但热门用户一天发几十条,还是会有不少查询。两个优化:

  1. 按IP缓存:同一IP 5分钟内查一次就行(用户不会突然跨省);
  2. 按用户缓存:用户当天第一次发帖查一次,之后直接用缓存结果。
python
def get_user_location(user_id):
    loc = redis.get(f"loc:{user_id}")
    if loc:
        return loc
    info = query_ip(get_user_ip(user_id))
    loc = format_location(info)
    redis.setex(f"loc:{user_id}", 86400, loc or "未知")  # 缓存一天
    return loc

几个容易翻车的细节

  • IPv6用户:手机流量一堆IPv6,接口必须支持IPv6查询,否则一半用户显示"未知"。(IP9支持)
  • 容错:查询失败就显示"未知"或者不显示,别让整条帖子的流程挂掉。
  • 老数据:平台规定属地是"发布时"的,不是"现在"的。所以用户搬家了,老帖子的属地不变,这是对的,别"修复"它。
  • 历史存量:功能上线时,对历史帖子要么统一不回填,要么只对近期帖子回填,别去全量扫一遍——容易把接口打挂。

总结

一个"IP属地"功能,本质就三件事:发布时查一次 → 存省级 → 展示时读库。技术上不难,难的是把缓存、容错、合规这些细节做好。

很多朋友问我有没有现成方案,我都是推荐拿免费接口先顶上。IP9 免注册,接口:https://www.ip9.com.cn