[API] 查询指定 IP 地址的位置信息
1. 接口描述
IP 库来源于网络,本项目不对结果的准确性负责,请在中国法律许可范围内使用.
接口地址: https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/<ip>(公开实例,见 1.1)
请求方法:GET
用途:查询任意 IP(IPv4 或 IPv6)的归属地,返回与本项目其他查询同一套多源聚合结果。
- IP 写在路径里,不是查询串:
/v1/location/106.224.145.147。IPv6 直接用标准写法(含:)即可,无需 URL 编码以外的特殊处理。 - 与「获取客户端公网 IP 及位置」共用同一个处理器与同一份 IP 库,区别只是"查谁":不带路径参数 = 查请求方自己,带 = 查指定地址。
- 出参结构与「获取客户端公网 IP 及位置」完全一致,见该页的字段表,此处不重复。
- 免鉴权规则同所有
/v1/*端点:节点配了access-token才需要Authorization: Bearer。 - 查 IP 归属地不需要目标是本项目节点、也不做连通性探测,只查库;因此查任何公网 IP 都是同样耗时。
1.1 公开实例
本项目对外开放了一个江苏节点,可以直接用它把本接口调通,无需令牌:
| 方式 | 地址 |
|---|---|
| 直连节点(推荐) | https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/<ip> |
| 经中间件转发 | https://middleware-1.api-ipw.wsmdn.top/v1/cn-jiangsu/location/<ip> |
两种写法都是「节点 / 接口 / 目标」三段:直连时端点本身就是节点,经中间件时多一段节点标识。
中间件入口的 /v1/ 前缀与 /middleware/ 前缀等价,用哪个都行。
公共实例是共享的,调试与小流量接入没问题,请勿高频轮询、批量抓取,也不要拿它当线上服务的依赖。
1.2 还有别的节点 —— 拨测控制台
上面的江苏节点只是节点池里的一个。节点池的入口是拨测控制台 https://boce.wsmdn.top:
登录后进「可用节点」页,能看到全部已启用节点的节点标识、归属地、归属池(定位 / 拨测)、
协议栈与在线状态,每行都能一键复制调用前缀 —— 把上面那个中间件地址换成控制台给你的入口域名,
再接上 /v1/<节点标识>/ 就是完整前缀,换节点只动中间那一段标识。
比自己搭一套省事的地方:
- 节点现成 —— 名单里的节点都是已经部署好的,不用自己找机器、装程序、配隧道。
- 入口现成 —— 统一走 HTTPS 转发,证书与反向代理不用自己操心。
- 一套地址调所有节点 —— 换节点只改标识,接口路径、参数、返回结构都不变。
- 池与栈标得很清楚 —— 定位类请求走定位池,拨测类走拨测池,两个池都有的节点两种都能接。
- 名单会自己更新 —— 新接入的节点自动出现在列表里,不需要改代码。
用它调本接口(可直接粘贴执行):
# 用列表里的江苏节点查一个 IP
curl https://middleware-1.api-ipw.wsmdn.top/v1/cn-jiangsu/location/106.224.145.147
# 换成别的节点:只改中间那一段标识
curl https://middleware-1.api-ipw.wsmdn.top/v1/<节点标识>/location/106.224.145.147
节点有上下线,离线的节点调用会失败(返回
502)——名单上标了在线状态,挑在线的用。
2. 输入参数
| 参数名称 | 类型 | 描述 |
|---|---|---|
ip(必选,路径) |
String | 要查询的 IP,IPv4 或 IPv6 均可,例如 /v1/location/106.224.145.147 |
路径中的 IP 不要带方括号。IPv6 形如
/v1/location/2400:3200::1。
3. 输出参数
与「获取客户端公网 IP 及位置」相同:顶层为「源名 → 该源结果」的字典,ip 字段回显被查询的地址。取值约定(未加载、出错、空字段、经纬度类型)也一致。
非法 IP 是"看起来成功"的:IP 传错时 HTTP 仍返回 200,但每个源会各自报错,形如:
{
"ip": "not-an-ip",
"ip2region": "error: parse ip not-an-ip: invalid ip address: not-an-ip",
"maxmind_city": "error: ParseAddr(\"not-an-ip\"): unable to parse IP",
"ip2location": { "country": "Invalid IP address.", "city": "Invalid IP address." },
"ip2location_asn": { "asn": "Invalid IP address.", "as": "Invalid IP address." }
}
所以判断成功与否要看字段内容,不能只看状态码:字段是对象才有结论;是 "error: ..." 字符串或 "Invalid IP address." 就是没查到。建议调用前先自行校验 IP 格式。
4. 示例
4.1 cURL 查询指定 IP 的位置
curl https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/106.224.145.147
# IPv6 同样直接拼:curl https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/2400:3200::1
# 经公共中间件转发(见 1.1):
# curl https://middleware-1.api-ipw.wsmdn.top/v1/cn-jiangsu/location/106.224.145.147
输出示例(节选,真实响应):
{
"ip": "106.224.145.147",
"ip2region": { "country": "中国", "administrative_area": "江西省", "city": "南昌市", "isp": "电信" },
"ip2location": {
"country": "China", "country_code": "CN", "administrative_area": "Jiangxi",
"city": "Ji'an", "zipcode": "343000", "timezone": "+08:00",
"latitude": "27.11716", "longitude": "114.97927"
},
"qqwry": { "country": "中国", "country_code": "CN", "administrative_area": "江西", "city": "吉安", "isp": "电信" },
"geocn": { "country": "中国", "administrative_area": "江西省", "city": "南昌市", "division_code": "360100", "isp": "电信" },
"maxmind_asn": { "asn": "AS4134", "org": "Chinanet" }
}
上面同一 IP 出现了南昌 / 吉安两种结论:这就是"多源并列、不做合并"的含义—— 各库口径与更新批次不同,写法也不统一(
江西省/Jiangxi、南昌市/Nanchang)。 想要单一结论请自行选源或做交叉投票。
4.2 Python
#!/usr/bin/python3
import requests
queryIP = '106.224.145.147'
r = requests.get('https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/' + queryIP)
data = r.json()
qqwry = data.get('qqwry', {})
if isinstance(qqwry, dict):
print(qqwry.get('country'), qqwry.get('administrative_area'),
qqwry.get('city'), qqwry.get('isp'))
else:
print('该源不可用:', qqwry)
4.3 Golang
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
queryIP := "106.224.145.147"
resp, err := http.Get("https://cn-jiangsu.api-ipw.wsmdn.top/v1/location/" + queryIP)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]json.RawMessage
if err := json.Unmarshal(body, &result); err != nil {
panic(err)
}
var loc struct {
Country string `json:"country"`
City string `json:"city"`
Isp string `json:"isp"`
}
if err := json.Unmarshal(result["qqwry"], &loc); err != nil {
fmt.Println("该源不可用,原始值:", string(result["qqwry"]))
return
}
fmt.Printf("%s %s %s\n", loc.Country, loc.City, loc.Isp)
}
5. 错误码
| 现象 | 说明 |
|---|---|
字段是 "Invalid IP address."(ip2location 系列) |
路径里的 IP 不合法。该库对非法输入仍返回对象,值里写明原因 |
字段是 "error: ... unable to parse IP" |
同上,其它源对非法输入直接返回错误字符串 |
404 page not found |
该节点 ipdb 已关闭,/v1/location/:ip 未注册 |
401 |
节点配了 access-token 但未携带正确的 Authorization: Bearer <access-token> |
| 结果与常识不符 | 免费 IP 库本身有偏差;本项目是多源并列,可交叉比对,不保证单一源正确 |