Skip to content

线上投票怎么限制地区?按IP归属地控制投票资格

办过线上评选活动的运营都有经验:很多活动主办方明确要求"仅限本省用户投票",比如社区最美街道评选、本地商家人气榜、学校十佳评选。不限制的话,外地水军一拥而上,票数完全失真。怎么低成本实现地区限制?用 IP 归属地在投票接口前加一道校验就行。

一、先分清两件事:地区限制 ≠ 防刷票

很多文章把这两件事混在一起,其实它们是两道独立的关卡:

  • 防刷票:同一用户不能反复投,靠 IP 频次、手机号、账号体系限制(类似电商防羊毛)
  • 地区限制:投票资格控制,不在指定区域的用户直接不能投

地区限制在业务上更靠前——先判断"有没有资格投",再谈"能不能重复投"。IP 归属地解决的就是前者。

二、实现方案:投票前先查归属地

流程:用户点投票 → 后端拿用户 IP → 查归属地 → 判断省份/城市是否在白名单 → 通过才执行投票逻辑。

python
import requests
import redis

cache = redis.Redis(host='127.0.0.1', port=6379, db=0)
ALLOWED_PROVS = {'浙江省'}  # 活动仅限浙江省

def vote(user_ip, candidate_id):
    # 1. 先查归属地(带缓存,避免每次投票都打接口)
    prov = cache.get(f'prov:{user_ip}')
    if not prov:
        r = requests.get(f'https://ip9.com.cn/get?ip={user_ip}', timeout=3)
        data = r.json()
        if data.get('ret') != 200:
            return {'ok': False, 'msg': '无法确认您的所在地区'}
        prov = data.get('prov', '')
        cache.setex(f'prov:{user_ip}', 3600, prov)  # 缓存 1 小时

    # 2. 地区资格校验
    if prov not in ALLOWED_PROVS:
        return {'ok': False, 'msg': '本活动仅限浙江省用户参与'}

    # 3. 通过后才执行投票 + 防刷校验(频次、账号等)
    return do_vote(candidate_id)

缓存很关键:免费接口 60 次/分钟/IP,投票活动有并发峰值,把归属地结果按 IP 缓存一小时,接口压力几乎可以忽略;同一 IP 短时间内归属地也不会变,缓存不影响准确性。

三、白名单粒度怎么定

IP9 免费版返回国家、省、市三级,按活动规则选粒度:

  • 全国性活动限制到省:比对 prov
  • 同城活动限制到市:比对 city(比如仅限杭州市)
  • 要更细的区县:VIP 版提供 area 字段(免费版 area 为空)

注意 lat/lng 是城市中心坐标,别拿来做"距离活动地点 5 公里内"这种精确判断,那是地图 SDK 的活。

四、几个容易踩的坑

  1. IPv6 用户:现在很多家庭宽带和手机网络已经用 IPv6,归属地接口必须支持 IPv6,否则这部分用户会被误判;
  2. 运营商 NAT 误伤:个别地区出口 IP 归属地会漂到邻省,白名单建议把相邻省份也纳入"待复核",不要直接拒绝,给用户留申诉通道;
  3. 代理/VPN:有人会用代理伪装地区,VIP 版的 ip_type 字段能识别 IDC 机房 IP,遇到机房 IP 的投票可以标记人工审核;
  4. 别把归属地当唯一依据:地区限制适合做"第一道闸",重要活动建议叠加手机号归属地或实名信息双重校验。

总结

给线上投票加地区限制,本质就是"投票前查一次 IP 归属地,比对白名单"。用 https://ip9.com.cn/get?ip=xxx 就能拿到省、市字段,免费版 60 次/分钟/IP 加上缓存完全扛得住,中国城市准确率 99.2% 也够用;想识别代理伪装再加 VIP 版的 ip_type。官网:https://www.ip9.com.cn