Appearance
个人网站10分钟接入免费IP查询接口(含完整代码)
给个人网站加个"IP属地"展示,听起来是个小功能,做起来也真的不大。这篇文章用最快的路子,带你10分钟内搞定。
我选的是 IP9,因为它的接口不需要注册、不需要key,直接一个GET就能查,最适合个人站这种"懒得折腾"的场景。
接口就一句话
http
GET https://ip9.com.cn/get?ip=1.2.3.4不传 ip 参数,就是查询访问者当前的IP,这个对我们来说正合适——我们不需要用户IP,服务器自己就知道访问者的IP,直接调接口即可。
服务端怎么写(后端给前端返回IP属地)
个人站一般都有个后端(PHP/Python/Node都行),让后端代查,避免跨域问题,也不暴露接口调用细节。
以 PHP 为例:
php
<?php
// 获取访问者IP
$ip = $_SERVER['REMOTE_ADDR'];
// 调IP9查询
$resp = file_get_contents("https://ip9.com.cn/get?ip=$ip");
$data = json_decode($resp, true);
if ($data && $data['ret'] == 200) {
$info = $data['data'];
echo json_encode([
'ip' => $info['ip'],
'prov' => $info['prov'],
'city' => $info['city'],
'isp' => $info['isp'],
]);
} else {
echo json_encode(['error' => '查询失败']);
}
?>Python(Flask) 版本:
python
from flask import Flask, jsonify, request
import requests
app = Flask(__name__)
@app.route("/ip-info")
def ip_info():
ip = request.remote_addr
r = requests.get(f"https://ip9.com.cn/get?ip={ip}", timeout=3)
data = r.json()
if data.get("ret") == 200:
d = data["data"]
return jsonify(ip=d["ip"], prov=d["prov"], city=d["city"], isp=d["isp"])
return jsonify(error="查询失败"), 500前端怎么展示
后端返回之后,前端直接渲染就行。下面是原生JS的一个极简示例:
html
<div id="ip-loc">正在获取IP属地...</div>
<script>
fetch('/ip-info')
.then(r => r.json())
.then(data => {
const el = document.getElementById('ip-loc');
if (data.city) {
el.textContent = `${data.prov} ${data.city} · ${data.isp || ''}`;
} else {
el.textContent = '归属地获取失败';
}
});
</script>别忘的两件事
1. 加缓存
同一个访客,每次刷新页面都去查一次接口,纯属浪费。正确做法是缓存起来,比如查完存进Session或者Redis,半小时内不重复查:
python
from functools import lru_cache
@lru_cache(maxsize=1024)
def query(ip):
...2. 注意限流
免费接口一般是按IP限流的,IP9是每个IP每分钟60次。个人站完全够用,但如果是缓存没做好、或者被刷,就可能触发限流。做个人功能别去压测它,够用就行。
上线前自检清单
- [ ] 后端能拿到正确的访问者IP(注意有没有走代理/CDN,有的话要取
X-Forwarded-For) - [ ] 查询失败时有兜底文案,别让页面白屏
- [ ] 加了缓存,避免重复请求
- [ ] 前端展示不出来时静默处理,不打扰访客
这套流程我给自己博客搭过,加起来真就10分钟的事。动手试试吧,接口在 https://www.ip9.com.cn 有完整文档。