IPconf
返回教程列表
API 10 分钟阅读

在应用里接入 IP 地理位置查询

用 JavaScript / Node.js / Python / Go 调用 ipconf API,并合理处理缓存、VPN 用户与隐私规则。

IP 地理位置能查到什么,查不到什么

IP 地理位置基于地址分配数据库,把 IP 映射到可能的国家、地区、城市。国家级一般 >95% 准确,地区级 75-90%,城市级 50-80%(视国家而定)。

它查不到街道地址、姓名或身份。对 VPN/代理用户、企业统一出口、移动 CGN、所有云/VPS IP 都会偏差。产品要做到:位置对了能用,位置错了也不阻塞用户。

选对接口

`/api/ip` 返回调用方自己的位置,适合"展示本地内容"。`/api/ip/{ip}` 查任意 IP,适合日志分析、风控、显示"此次登录来自 X"。

加 `?lang=zh` 返回中文地名。默认英文。两个接口返回相同 schema。

// 浏览器查当前访问者:
fetch("https://api.ipconf.me/api/ip")
  .then(r => r.json())
  .then(data => console.log(data.country, data.city));

// 查指定 IP:
fetch("https://api.ipconf.me/api/ip/8.8.8.8?lang=zh")
  .then(r => r.json())
  .then(data => console.log(data));

前端调用 vs 后端调用

浏览器调用用的是浏览器的 IP——查当前访问者通常这样就够。但 API URL 会暴露给每个访客,还受广告拦截和 CORS 影响。

后端调用默认用服务器自己的出口 IP,要查访客的就得显式把 IP 当路径参数传。后端调用能缓存、重试、统一处理错误。

// Node.js:从请求里取访客 IP,再去查:
app.get("/local-content", async (req, res) => {
  const visitorIp = req.headers["cf-connecting-ip"]
    || req.headers["x-forwarded-for"]?.split(",")[0]
    || req.ip;
  const r = await fetch(`https://api.ipconf.me/api/ip/${visitorIp}`);
  const geo = await r.json();
  res.json({ visitor: visitorIp, country: geo.country });
});

缓存策略

家宽用户的 IP-位置映射在分钟到小时尺度上稳定;固定基础设施 IP 在小时到天尺度上稳定。基本不会有"一分钟内查同一个 IP 两次还需要重查"的需求。

进程内 LRU 缓存(10-60 分钟 TTL)是最简单的起点。多机部署加 Redis。不要永久缓存——IP 分配会变,旧数据会让真实用户看到错的内容。

// Node.js + 简易 LRU + TTL:
import { LRUCache } from "lru-cache";
const cache = new LRUCache({ max: 10000, ttl: 30 * 60 * 1000 });

async function geo(ip) {
  if (cache.has(ip)) return cache.get(ip);
  const r = await fetch(`https://api.ipconf.me/api/ip/${ip}`);
  const data = await r.json();
  cache.set(ip, data);
  return data;
}

处理 VPN、代理、CDN 用户

可观比例的流量是 VPN/代理用户。他们的位置是 VPN 出口节点,不是真实位置。对这类用户有影响的功能(区域限制内容、地区定价、"附近门店")一定要给显式的手动覆盖入口——别让用户因为定位错被永久卡住。

在 Cloudflare 等 CDN 后面,源站看到的是边缘节点 IP。要读 `CF-Connecting-IP` 或 `X-Forwarded-For` 后再去查,否则每个访客都"在旧金山"。

// Python(Flask 示例):
from flask import request
import requests

def visitor_geo():
    ip = (
        request.headers.get("CF-Connecting-IP")
        or request.headers.get("X-Forwarded-For", "").split(",")[0].strip()
        or request.remote_addr
    )
    r = requests.get(f"https://api.ipconf.me/api/ip/{ip}", timeout=2)
    return r.json() if r.ok else None

隐私与 GDPR

在欧盟和不少其他司法管辖区,IP 与其他数据结合即构成个人数据。查询本身一般没问题,把结果绑定到用户账户长期保存就要重新评估了。

实操原则:只保存业务真需要的字段;不要无限期持久化精确查询结果;隐私政策里说明这项处理;为依赖地理位置的功能提供关闭入口。把 geo 当作软提示,不当作身份断言。

其他语言示例

接口就是 HTTP + JSON,任何语言都能用。下面给 Python 和 Go 的最小示例。超时、重试、缓存按前面几节的模式自行添加。

# Python(requests):
import requests
r = requests.get("https://api.ipconf.me/api/ip/1.1.1.1", timeout=2)
print(r.json()["country"])

# Go(net/http):
package main

import (
  "encoding/json"
  "net/http"
  "fmt"
)

func main() {
  r, _ := http.Get("https://api.ipconf.me/api/ip/1.1.1.1")
  defer r.Body.Close()
  var data map[string]any
  json.NewDecoder(r.Body).Decode(&data)
  fmt.Println(data["country"])
}