Appearance
社交平台那个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 存进帖子记录,展示时直接查字段渲染,不碰接口。
缓存怎么做
虽然每帖只查一次,但热门用户一天发几十条,还是会有不少查询。两个优化:
- 按IP缓存:同一IP 5分钟内查一次就行(用户不会突然跨省);
- 按用户缓存:用户当天第一次发帖查一次,之后直接用缓存结果。
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