17NAS DEVELOPER API

IP查询 API

一个请求拿到访问者的真实 IP、走的是 IPv4 还是 IPv6、国家地区、ASN、运营商和时区。国内直连,支付宝付款。

17nas.com 的IPv6 检测工具本身就跑在这套边缘上——本站至今已完成 172,668 次检测,你在本站做的每一次检测,走的都是同一条链路。

接口地址
ipapi.17nas.com
认证方式
Bearer API Key
输出格式
JSON / Text
curl
curl https://ipapi.17nas.com/v1/ip \
  -H "Authorization: Bearer 17nas_live_xxx"
{
  "ip": "203.0.113.10",
  "protocol": "IPv4",
  "country": { "code": "CN" },
  "asn": { "number": 4134 },
  "edge": { "colo": "HKG" }
}
累计检测
172,668 次
独立 IP
52,755 个
近 30 天
26,105 次
服务节点
全球边缘网络
LIVE DEMO

不用注册,先看它能不能跑

点一下,用你现在这条网络的真实 IP 调一次公共端点,看到的是没有加工过的原始返回。注意这里演示的是公共端点,字段结构与带 Key 的 /v1/ip 不同,后者以下方文档为准。

GET https://ip.17nas.com?format=json
点击上面的按钮,这里会显示真实返回结果。
刚才调的是公共端点,适合临时查询和手动排查。

一旦要接进你自己的网站、APP、小程序或服务端脚本,就需要 API Key:公共端点没有独立额度、没有调用统计、没有错误记录、也没有 IP 白名单,随时可能因为被滥用而限流,出问题你查不到任何日志。

免费领 1,000 次/月开发额度
USE CASES

大家都拿它做什么

下面每段代码都可以直接复制去跑,把 17nas_live_xxx 换成你自己的 Key 就行。

家宽 IP 一变就更新 DDNS

家庭宽带的公网 IP 随时会变,NAS 的域名就会指向一个不存在的地址。用 cron 每 5 分钟查一次,只有变了才去调 DNS 服务商的接口——比无脑每次都更新省事,也不会把 DNS 接口的额度打满。

ddns-update.sh
#!/bin/bash
# crontab: */5 * * * * /opt/ddns-update.sh
KEY="17nas_live_xxx"
CACHE="/tmp/.last_wan_ip"

IP=$(curl -fsS --max-time 10 "https://ipapi.17nas.com/v1/ip?format=text" \
      -H "Authorization: Bearer $KEY") || exit 0

# 拿不到或者跟上次一样就直接退出,不打扰 DNS 服务商
[ -z "$IP" ] && exit 0
[ "$IP" = "$(cat "$CACHE" 2>/dev/null)" ] && exit 0

echo "$IP" > "$CACHE"
logger -t ddns "WAN IP changed to $IP"

# 换成你自己的 DNS 服务商接口
curl -fsS -X POST "https://dns.example.com/api/record" \
  -d "name=nas.example.com&type=A&value=$IP"

公网 IP 变动微信告警

不想自动改 DNS,只想知道"我家 IP 什么时候变了"。IP 一变就推一条到微信,顺带把运营商和归属地一起报出来——运营商换了池子的时候特别有用。

wan_watch.py
import json, pathlib, requests

KEY = "17nas_live_xxx"
PUSH = "https://www.pushplus.plus/send"   # 换成你自己的推送通道
TOKEN = "your_pushplus_token"
CACHE = pathlib.Path("/var/tmp/wan_ip.json")

r = requests.get(
    "https://ipapi.17nas.com/v1/ip",
    headers={"Authorization": f"Bearer {KEY}"},
    timeout=10,
)
r.raise_for_status()
now = r.json()

# 剩余额度就在响应头里,不用额外查一次
print("本月剩余调用:", r.headers.get("X-Quota-Remaining"))

last = json.loads(CACHE.read_text()) if CACHE.exists() else {}
if last.get("ip") == now["ip"]:
    raise SystemExit(0)

CACHE.write_text(json.dumps(now))
requests.post(PUSH, json={
    "token": TOKEN,
    "title": f"公网 IP 变了:{now['ip']}",
    "content": (
        f"协议 {now['protocol']}\n"
        f"运营商 {now['asn']['organization']} (AS{now['asn']['number']})\n"
        f"地区 {now.get('city') or '-'} / {now['country']['code']}\n"
        f"原 IP {last.get('ip', '无记录')}"
    ),
}, timeout=10)

异地登录风控

用户登录时记下 IP 的归属地和 ASN。下次换了个省、或者从家宽跳到机房 IP,就触发二次验证。这比单纯记 IP 靠谱——家宽 IP 本来就天天变,但归属地和运营商不会。

login_risk.php
<?php
/** 登录成功后调用,返回是否需要二次验证 */
function login_needs_verify(PDO $pdo, int $userId): bool
{
    $ch = curl_init('https://ipapi.17nas.com/v1/ip');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_HTTPHEADER => ['Authorization: Bearer 17nas_live_xxx'],
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // 风控接口挂了不能把用户挡在门外,降级放行
    if ($status !== 200 || !$body) {
        error_log('ip-api unavailable, skip risk check');
        return false;
    }

    $now = json_decode($body, true);
    $fingerprint = $now['country']['code'] . '|' . $now['region'] . '|' . $now['asn']['number'];

    $stmt = $pdo->prepare('SELECT ip_fingerprint FROM user_login_env WHERE user_id = ?');
    $stmt->execute([$userId]);
    $known = $stmt->fetchColumn();

    $pdo->prepare('REPLACE INTO user_login_env (user_id, ip_fingerprint, updated_at) VALUES (?, ?, NOW())')
        ->execute([$userId, $fingerprint]);

    return $known !== false && $known !== $fingerprint;
}

按 IPv4/IPv6 决定回源

双栈环境下,用户走 IPv6 进来但你的后端只有 IPv4,中间那一跳的转换会白白多花几十毫秒。先判断协议,再决定走哪条回源链路或者返回哪套资源地址。

origin-select.js
const KEY = process.env.IP_API_KEY;

async function pickOrigin() {
  const res = await fetch('https://ipapi.17nas.com/v1/ip', {
    headers: { Authorization: `Bearer ${KEY}` },
    signal: AbortSignal.timeout(5000),
  });

  if (res.status === 429) {
    // 额度用尽或触发限速,X-Quota-Reset 告诉你什么时候恢复
    console.warn('quota/rate limited, reset at', res.headers.get('X-Quota-Reset'));
    return ORIGINS.v4;   // 降级到默认线路,不要抛错
  }
  if (!res.ok) return ORIGINS.v4;

  const { protocol, edge } = await res.json();
  console.log('edge colo:', edge.colo);
  return protocol === 'IPv6' ? ORIGINS.v6 : ORIGINS.v4;
}

const ORIGINS = {
  v4: 'https://origin-v4.example.com',
  v6: 'https://origin-v6.example.com',
};

小程序 / APP 日志留存

小程序和 APP 上架要求留存用户操作日志,其中 IP 和归属地是必填项。关键点是必须在服务端调——把 Key 打进前端安装包,等于把你的额度送给所有人。

audit_log.php
<?php
/**
 * 服务端记录一条合规日志。
 * 注意:Key 只能放在服务端。小程序/APP 端把请求打到你自己的服务器,
 * 由服务器再去调 17NAS,前端永远接触不到 Key。
 */
function write_audit_log(PDO $pdo, int $userId, string $action): void
{
    $ctx = ['ip' => null, 'country' => null, 'isp' => null];

    $ch = curl_init('https://ipapi.17nas.com/v1/ip');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('IP_API_KEY')],
    ]);
    if ($body = curl_exec($ch)) {
        $data = json_decode($body, true);
        $ctx = [
            'ip' => $data['ip'] ?? null,
            'country' => $data['country']['code'] ?? null,
            'isp' => $data['asn']['organization'] ?? null,
        ];
    }
    curl_close($ch);

    $pdo->prepare(
        'INSERT INTO audit_logs (user_id, action, ip, country, isp, created_at)
         VALUES (?, ?, ?, ?, ?, NOW())'
    )->execute([$userId, $action, $ctx['ip'], $ctx['country'], $ctx['isp']]);
}

多线路出口 IP 巡检

手上有一堆 VPS、代理或者多拨线路,想确认每条线路真实的出口 IP 和落地机房。挨个跑一遍,出口不对的立刻能发现。

egress-check.sh
#!/bin/bash
KEY="17nas_live_xxx"
IFACES=("eth0" "eth1" "wg0")

printf "%-8s %-40s %-10s %s\n" "接口" "出口IP" "协议" "运营商"
for IF in "${IFACES[@]}"; do
  JSON=$(curl -fsS --max-time 8 --interface "$IF" \
          "https://ipapi.17nas.com/v1/ip" \
          -H "Authorization: Bearer $KEY" 2>/dev/null)

  if [ -z "$JSON" ]; then
    printf "%-8s %-40s %-10s %s\n" "$IF" "(不通)" "-" "-"
    continue
  fi

  printf "%-8s %-40s %-10s %s\n" \
    "$IF" \
    "$(echo "$JSON" | jq -r .ip)" \
    "$(echo "$JSON" | jq -r .protocol)" \
    "$(echo "$JSON" | jq -r .asn.organization)"
done
COMPARISON

要不要自己搭一个?

取一个真实 IP 本身不难,难的是长期维护它。下面是三条路各自要付出的成本。

对比项 自己搭 国外服务 17NAS
国内访问延迟取决于你的服务器跨境,波动大边缘就近响应
IPv6 支持要自己配双栈多数支持原生双栈
GeoIP / ASN 库更新自己下载、自己更新服务方维护服务方维护
日常维护证书、机器、监控全归你无无
调用统计与错误记录要自己写有控制台自带
支付方式—多数只收信用卡支付宝
出问题找谁找自己英文工单,隔时区中文反馈,同时区
起步成本一台服务器 + 时间按量计费免费 1,000 次/月

说句公道话:如果你只是个人玩票、每天调几次,自己用 Nginx 返回 $remote_addr 就够了,不用花这个钱。真正值得买的是那些"挂了会有人找你"的场景——线上业务、要留存日志、要长期稳定跑的自动化。

PLANS

API套餐

额度用完就停止调用,不会产生欠费,也不会自动扣款。年度套餐按月释放额度。

注册就能用,不用付钱

注册开发者可创建 1 个 API Key,每月 1,000 次调用额度,IPv4 与 IPv6 共用。够你把接入调通再决定要不要买。仅限个人开发测试,商业使用请选下方套餐。

免费创建 API Key

API开发版

¥19.9/月
  • 100,000 次/月
  • 5 QPS 并发
  • 1 个 API Key
  • 不支持白名单
  • 7 天错误记录
  • 允许商业使用

API商业版

¥299.0/月
  • 5,000,000 次/月
  • 50 QPS 并发
  • 5 个 API Key
  • 100 条 IP/CIDR 白名单
  • 90 天错误记录
  • 允许商业使用

企业定制

¥999/月起
  • 定制额度与并发
  • 合同与专属 SLA
  • 专属技术支持
  • 可私有化部署
联系我们
额度不够用?不用急着升级

已有付费套餐的用户可以随时加购一次性加量包:¥14.90 / 100,000 次、¥59.90 / 1,000,000 次。加量包叠加在本期额度之上,随本期一起到期,不自动续费。在控制台直接购买。

当前支持的支付方式:Stripe。企业合同 SLA 与普通商业套餐分开提供。

DATA

顺便说个数据:IPv6 在中国普及到什么程度了

基于 17NAS 访客在 2026 年 2 月 5 日 至今的 172,668 次真实检测(52,755 个独立 IP)。这些检测走的就是本页在卖的这套边缘网络。

双栈(IPv4 + IPv6)最理想的状态,两种协议都能用
61.2%103,190 次
仅 IPv4还没开通 IPv6,或路由器/防火墙没放行
35.8%60,458 次
仅 IPv6较少见,部分移动网络和纯 IPv6 环境
1.4%2,300 次
未取到结果弱网、超时或代理环境下的检测失败
1.6%2,763 次

合计 62.5% 的访客具备 IPv6 能力。需要说明的是:会主动来 17NAS 测 IPv6 的人,本身就比普通网民更关心 IPv6,所以这个样本存在自选择偏差,不能当作全国普及率,只能反映"关心 IPv6 的这批人"的实际情况。数据每小时更新。想测测你自己的网络?IPv6 检测工具在这里。

REFERENCE

接口文档

先看下面的三步接入,五分钟能跑通第一个请求;细节再往下翻。

  1. 1
    创建 API Key

    登录后在控制台点「创建 API Key」。密钥只完整显示一次,服务端只存哈希,丢了只能重新生成。

    去控制台创建
  2. 2
    带上 Bearer 头发一个请求

    把密钥放进 Authorization 头,直接请求 /v1/ip。

    看请求示例
  3. 3
    读响应头里的额度

    每次成功响应都带 X-Quota-Remaining,不用额外调接口查用量。

    看响应头说明

身份认证

在服务端请求的 Authorization 头中发送 Bearer 密钥。

Authorization: Bearer 17nas_live_xxxxxxxxx

不要把密钥放进浏览器脚本、APP 或小程序安装包——这些都能被反编译出来。前端需要用时,让前端请求你自己的服务器,由服务器代为调用。可以在控制台配置 IP/CIDR 白名单进一步限制来源。

GET/v1/ip

ipapi.17nas.com

返回本次 HTTP 连接实际使用的 IP 和协议。请求走 IPv4 就返回 IPv4,走 IPv6 就返回 IPv6,不需要额外指定。

参数位置说明
AuthorizationHeader必填。Bearer <你的 API Key>
formatQuery可选。json(默认)或 text;text 只返回纯 IP,适合 shell 直接取值
# JSON(默认)
curl https://ipapi.17nas.com/v1/ip \
  -H "Authorization: Bearer 17nas_live_xxx"

# 只要 IP 纯文本,适合 shell 脚本直接取值
curl "https://ipapi.17nas.com/v1/ip?format=text" \
  -H "Authorization: Bearer 17nas_live_xxx"

# 强制走 IPv4 / IPv6 查询,用 curl 自己的参数控制
curl -4 https://ipapi.17nas.com/v1/ip -H "Authorization: Bearer 17nas_live_xxx"
curl -6 https://ipapi.17nas.com/v1/ip -H "Authorization: Bearer 17nas_live_xxx"

响应字段

200 OK
{
  "ip": "203.0.113.10",
  "protocol": "IPv4",
  "country": { "code": "CN" },
  "region": "Guangdong",
  "city": "Shenzhen",
  "timezone": "Asia/Shanghai",
  "asn": { "number": 4134, "organization": "CHINANET" },
  "edge": { "colo": "HKG" },
  "request_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "generated_at": "2026-07-26T09:00:00.000Z"
}
字段类型说明
ipstring本次连接的公网 IP
protocolstringIPv4 或 IPv6
country.codestringISO 3166-1 两位国家代码,取不到为 null
region / citystring省/州与城市,英文;精度取决于边缘库,可能为 null
timezonestringIANA 时区名,如 Asia/Shanghai
asn.numbernumber自治域号;取不到为 0
asn.organizationstring运营商名称,可能为 null
edge.colostring处理本次请求的边缘节点三字码
request_idstring本次请求的唯一 ID,反馈问题时带上它

地理位置字段依赖边缘节点的 GeoIP 数据,移动网络、卫星链路、企业 NAT 出口和部分代理下可能不准或为空。请把这些字段当参考而不是事实,不要用它做强制性的地域拦截。

额度响应头

每次成功响应都会带上当前额度状态,不需要额外调接口去查。

响应头说明
X-RateLimit-Limit每秒允许的请求数(QPS)
X-RateLimit-Remaining当前这一秒还剩多少次
X-RateLimit-Reset限速窗口重置的 Unix 时间戳
X-Quota-Limit本期总额度
X-Quota-Used本期已用
X-Quota-Remaining本期剩余
X-Quota-Reset本期额度重置时间
X-Request-Id本次请求 ID,反馈问题时带上它

建议在代码里监控 X-Quota-Remaining,低于 10% 时告警,别等到调用直接失败才发现。

错误状态

401 密钥无效、已吊销或格式不对 403 来源 IP 不在白名单内 429 超过 QPS 限速,或本期额度耗尽 503 服务暂时不可用,稍后重试
{
  "error": {
    "code": "quota_exhausted",
    "message": "Monthly quota exhausted",
    "request_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "docs_url": "https://17nas.com/ip-api.php#documentation",
    "upgrade_url": "https://17nas.com/ip-api.php?source=api-error&placement=quota-exhausted#pricing",
    "reset_at": "2026-08-01T00:00:00+08:00"
  }
}

429 有两种成因,靠响应头区分:X-RateLimit-Remaining 为 0 是瞬时限速,等一秒就能继续;X-Quota-Remaining 为 0 是本期额度用尽,要等到 reset_at 或者加量/升级。

重试与降级

这是一个网络请求,它一定会有失败的时候。几条实践建议:

  • 设置 5 秒以内的超时,不要让它拖垮你的主流程
  • 遇到 503 或超时可以重试,用指数退避(1s、2s、4s),最多 3 次
  • 遇到 401 / 403 不要重试,那是配置问题,重试只会浪费额度
  • 遇到 429 且是额度耗尽,重试没有意义,直接走降级逻辑
  • 非关键路径(比如日志记录)失败就跳过,别因为拿不到 IP 归属地把用户的正常操作挡下来
  • 可以在本地缓存几分钟——同一台服务器的出口 IP 通常不会秒级变化
FAQ

买之前你可能想问的

免费额度能商用吗?

不能。免费的 1,000 次/月仅限个人开发测试。任何对外提供服务的场景——你的网站、APP、小程序、给客户交付的系统——都需要购买商业套餐。付费套餐会在控制台显示“允许商业使用”。

额度用完了会怎样?会不会自动扣费?

不会。额度用完后接口直接返回 429 并停止调用,不产生任何欠费,也不会自动扣款。你可以等下个周期自动恢复,或者买个加量包立刻续上。我们不做“先用后付”,就是为了避免你哪天被 bug 死循环打出一张天价账单。

年付的额度是一次性给完吗?

不是,按月释放。比如买一年 API Pro,是每个月给 100 万次、连续给 12 个月,不是一次性给 1200 万次。这样设计是为了防止额度在头一个月被异常调用一次性打光。每个月的剩余额度不累积到下个月。

付款后多久能用?

支付成功后新额度会在 1 分钟内同步到全球边缘节点。同步完成前的调用仍按原额度计算,不会白扣。控制台的订单状态变成“已完成”就代表已经生效。

支持退款吗?

API 额度属于虚拟商品,额度一经发放原则上不支持退款。但如果是我们这边的原因导致服务不可用,或者你付款后额度没有正常到账,请带上订单号到反馈页找我们,会逐单处理。建议先用免费额度把接入调通再购买。

API Key 泄露了怎么办?

立刻去控制台吊销这个 Key 并新建一个,吊销会在 1 分钟内同步到边缘。为了防患于未然,建议提前配好 IP/CIDR 白名单——这样即使 Key 泄露,别人在你的服务器 IP 之外也用不了。

我可以中途升级套餐吗?

可以,在控制台点“升级套餐”,只补差价,服务到期时间不变。注意升级需要保持当前的计费周期(月付升月付、年付升年付)。想从月付转年付,在续费时选年付即可。

数据存在哪里?会记录我查了什么吗?

调用记录只保存聚合的用量统计(每小时的成功/失败次数、平均耗时)和错误日志。错误日志里的来源 IP 是脱敏后存储的,保留天数按套餐而定(7 天起)。我们不会保存你每次查询返回的具体 IP 内容。

服务稳定性怎么保证?

接口部署在全球边缘网络上,请求由离用户最近的节点就近响应,不回源到单点服务器,任何一个地区的节点异常都不会导致整体不可用。需要合同化 SLA 承诺的,请选择企业定制方案。

还是拿不定主意?

那就先用免费额度把接入调通。跑通了再决定要不要买,反正不花钱。