公开接口 · 无需鉴权 · 支持跨域 · 数据来源 scplist.kr
本站提供两个公开只读接口,可用于获取 SCP: Secret Laboratory(SCP:秘密实验室)的在线服务器列表, 并按访客地理位置就近排序,同时可查询单台服务器的历史在线人数曲线。
| 接口 | 用途 |
|---|---|
GET /api.php | 获取在线服务器列表(支持按访客 IP 距离排序、搜索、国家/版本筛选) |
GET /history.php | 获取指定服务器的历史在线人数(24 小时 / 7 天 / 30 天) |
# 取离某个访客最近的 5 台服务器
curl "https://scpslserver.com/api.php?ip=223.5.5.5&sort=distance_asc&limit=5"
# 查某台服务器最近 24 小时的在线人数
curl "https://scpslserver.com/history.php?server_id=56351&range=24h"
| 项目 | 说明 |
|---|---|
| 请求方式 | 仅 GET(另支持 OPTIONS 预检) |
| 协议 | HTTPS(HTTP 会自动跳转到 HTTPS) |
| 鉴权 | 无需鉴权,不需要 API Key 或 Token |
| 响应格式 | JSON,Content-Type: application/json; charset=utf-8 |
| 跨域 CORS | 已开放 Access-Control-Allow-Origin: *,可在浏览器前端直接 fetch |
| 字符编码 | UTF-8,中文不转义(未使用 \uXXXX) |
| 数据缓存 | 服务器列表每 60 秒从上游刷新一次,期间返回缓存数据 |
| 时间格式 | 所有时间均为 Unix 时间戳(秒) |
| 调用统计 | 每次外部调用会计入首页显示的「已被调用次数」 |
返回当前全部在线服务器,可按访客 IP 计算距离并排序。
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
ip | string | 否 | 请求来源 IP | 用于计算距离的访客 IPv4 地址。第三方对接时传入你自己用户的 IP,即可得到「对该用户就近排序」的结果。不传则使用请求来源 IP(即你服务器的 IP)。 仅支持 IPv4,IPv6 暂不支持定位。 |
sort | string | 否 | distance_asc |
排序方式,可选值:distance_asc 距离由近到远distance_desc 距离由远到近players_desc 在线人数由多到少players_asc 在线人数由少到多传入非法值时自动回退为 distance_asc
|
search | string | 否 | 空 | 按服务器名称模糊搜索(不区分大小写,匹配去除 HTML 标记后的纯文本名称) |
country | string | 否 | 空 | 按国家/地区代码精确筛选,两位 ISO 3166-1 代码,如 CN、US、RU(不区分大小写) |
version | string | 否 | 空 | 按游戏版本精确筛选,如 14.2.7。可用版本及其数量见返回的 version_stats |
limit | int | 否 | 0 |
限制返回的服务器数量(在排序之后截断)。0 或不传表示返回全部 |
country_stats 与 version_stats 始终基于全部在线服务器统计,
不受 search / country / version 筛选影响,方便你用来渲染筛选下拉框。
| 字段 | 类型 | 说明 |
|---|---|---|
client | object | 访客定位信息,见下表 |
stats | object | 全局统计,见下表 |
country_stats | object | 各国服务器数量,形如 {"RU":255,"CN":251},按数量降序 |
version_stats | object | 各版本服务器数量,形如 {"14.2.7":1153},按数量降序 |
updated_at | int | 服务器列表数据的更新时间(Unix 时间戳) |
api_count | int | 本站 API 累计被外部调用次数 |
total | int | 本次实际返回的服务器数量(已应用筛选与 limit) |
sort | string | 本次生效的排序方式 |
servers | array | 服务器数组,见下表 |
| 字段 | 类型 | 说明 |
|---|---|---|
ip | string | 本次用于定位的 IP |
country_code | string | 国家代码,如 CN;无法识别时为空字符串 |
country | string | 国家名(英文) |
city | string | 城市(中国 IP 返回中文如「杭州市」,海外返回英文) |
state | string | 省 / 州 |
lat / lon | float\|null | 纬度 / 经度;无法定位时为 null |
precision | string | 定位精度:city / province / country / unknown |
| 字段 | 类型 | 说明 |
|---|---|---|
online_servers | int | 当前在线服务器总数 |
online_users | int | 当前所有服务器在线玩家总数 |
display_servers | int | 上游展示的服务器数 |
offline_servers | int | 已注册但当前离线的服务器数(仅总数,无明细) |
| 字段 | 类型 | 说明 |
|---|---|---|
server_id | int | 服务器 ID,查询历史人数时使用此值 |
account_id | int | 服主账号 ID(同一服主的多台服务器该值相同) |
ip | string | 服务器 IP 地址 |
port | int | 游戏端口 |
online | bool | 是否在线(本接口只返回在线服务器,故通常为 true) |
version | string | 游戏版本,如 14.2.7 |
iso_code | string | 国家代码,如 CN |
country_name | string | 国家名(英文),如 China |
city | string | 服务器所在城市;无数据时为空字符串 |
state | string | 服务器所在省 / 州;无数据时为空字符串 |
players | string | 玩家数原始字符串,如 "27/30" |
players_current | int | 当前在线人数 |
players_max | int | 最大人数(槽位) |
info | string | 服务器名称原始值,含服主自定义的 HTML 颜色标记 |
info_text | string | 服务器名称纯文本(已剥离 HTML),推荐使用此字段 |
distance_km | float\|null | 访客到该服务器的距离(公里,保留 1 位小数);无法计算时为 null |
distance_precision | string | 该距离的可信精度,取访客与服务器两侧较低的那个 |
geo_precision | string | 该服务器自身的定位精度 |
lat / lon | float\|null | 服务器经纬度,可用于地图打点 |
modded | bool | 是否为模组服 |
whitelist | bool | 是否开启白名单 |
friendly_fire | bool | 是否开启友军伤害 |
official | int | 是否官方服(1 是 / 0 否) |
tech_list | array | 插件列表,元素为 {"name":"EXILED","version":"9.14.2"} |
pastebin | string | 服务器详情 pastebin ID,完整地址为 https://pastebin.com/{值} |
info 字段包含服主可自定义的 HTML 内容,直接插入页面存在 XSS 风险。
请使用 info_text,或对 info 做严格转义后再渲染。
{
"client": {
"ip": "223.5.5.5",
"country_code": "CN",
"country": "China",
"city": "杭州市",
"state": "浙江省",
"lat": 30.29365,
"lon": 120.16142,
"precision": "city"
},
"stats": {
"online_servers": 1176,
"online_users": 4642,
"display_servers": 1176,
"offline_servers": 21888
},
"country_stats": { "RU": 255, "CN": 251, "US": 147 },
"version_stats": { "14.2.7": 1153, "14.2.6": 8 },
"updated_at": 1787258650,
"api_count": 128,
"total": 2,
"sort": "distance_asc",
"servers": [
{
"server_id": 102246,
"account_id": 36206,
"ip": "120.27.160.16",
"port": 2000,
"online": true,
"version": "14.2.7",
"iso_code": "CN",
"country_name": "China",
"city": "杭州市",
"state": "浙江省",
"players": "3/22",
"players_current": 3,
"players_max": 22,
"info": "<b><span style=\"color:#0ff\">[CN]</span> Grass动态服</b>",
"info_text": "[CN] Grass动态服",
"distance_km": 0,
"distance_precision": "city",
"geo_precision": "city",
"lat": 30.29365,
"lon": 120.16142,
"modded": true,
"whitelist": false,
"friendly_fire": false,
"official": 0,
"pastebin": "V51ZhSiz",
"tech_list": [ { "name": "EXILED", "version": "9.14.2" } ]
}
]
}
查询指定服务器的历史在线人数曲线。本站每 10 分钟采集一次全部服务器人数,数据保留 30 天。
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
server_id | int | 是 | — | 服务器 ID,从服务器列表接口的 servers[].server_id 获取 |
range | string | 否 | 24h |
时间范围与聚合粒度:24h 最近 24 小时,按 10 分钟聚合(最多 144 点)7d 最近 7 天,按 1 小时聚合(最多 168 点)30d 最近 30 天,按 6 小时聚合(最多 120 点)传入非法值时自动回退为 24h
|
| 字段 | 类型 | 说明 |
|---|---|---|
server_id | int | 查询的服务器 ID |
server | object\|null | 服务器基本信息快照:server_id、name、ip、port、iso_code;从未采集到该服务器时为 null |
range | string | 本次生效的时间范围 |
bucket_seconds | int | 数据点聚合粒度(秒):600 / 3600 / 21600 |
summary | object | 区间汇总,见下表 |
collect_since | int\|null | 本站最早一条采集记录的时间戳,用于判断数据覆盖范围 |
total_points | int | 返回的数据点数量 |
points | array | 数据点数组(按时间升序),见下表 |
| 字段 | 类型 | 说明 |
|---|---|---|
avg | float\|null | 区间内平均在线人数(1 位小数) |
peak | int\|null | 区间内最高在线人数 |
min | int\|null | 区间内最低在线人数 |
samples | int | 区间内采样次数 |
latest | object\|null | 最新一条记录:players_current、players_max、recorded_at |
| 字段 | 类型 | 说明 |
|---|---|---|
ts | int | 该时间桶的起始时间戳 |
avg | float | 桶内平均在线人数 |
peak | int | 桶内最高在线人数 |
min | int | 桶内最低在线人数 |
slots | int | 该时段的最大人数(槽位) |
samples | int | 该桶包含的采样次数 |
points 为空数组,说明该时间范围内尚无数据,
可结合 collect_since 判断已积累多久。
{
"server_id": 56351,
"server": {
"server_id": 56351,
"name": "[US EAST] Dr. Bright's Facility #1",
"ip": "104.234.220.126",
"port": 7777,
"iso_code": "US"
},
"range": "24h",
"bucket_seconds": 600,
"summary": {
"avg": 42.3,
"peak": 48,
"min": 12,
"latest": {
"players_current": 48,
"players_max": 48,
"recorded_at": 1787258650
},
"samples": 144
},
"collect_since": 1787258650,
"total_points": 144,
"points": [
{ "ts": 1787258400, "avg": 42.5, "peak": 48, "min": 37, "slots": 48, "samples": 1 }
]
}
距离使用 Haversine 球面距离公式计算,单位为公里。定位策略如下:
| IP 类型 | 使用的库 | 说明 |
|---|---|---|
| 中国 IP | ip2region | 国内数据源,城市级命中率高;再通过中国城市坐标表转经纬度 |
| 海外 IP | GeoLite2 City | 直接返回城市级经纬度 |
| 精度值 | 含义 | 可信度 |
|---|---|---|
city | 城市级 | 距离较准确,可直接用于就近排序 |
province | 省级 | IP 库无城市数据,退到省会坐标,距离为近似值 |
country | 国家级 | IP 库仅有国家数据,误差可能达数百公里 |
unknown | 无法定位 | 此时 distance_km 为 null |
distance_precision 为 province 或 country 时,
建议在界面上加「约」「≈」等标识,避免给用户造成精确的错觉。本站前端即采用此做法。
| HTTP 状态 | 响应内容 | 原因与处理 |
|---|---|---|
200 | 正常 JSON | 成功。注意:即使 servers / points 为空数组也返回 200 |
204 | 空 | OPTIONS 预检请求的正常响应 |
400 | {"error":"缺少或无效的 server_id 参数"} | 调用 history.php 时未传或传了非法 server_id |
500 | {"error":"历史数据库不可用"} | 历史数据库读取失败,请稍后重试或反馈 |
502 | {"error":"无法获取服务器列表,请稍后重试"} | 上游 scplist.kr 不可用或超时,建议稍后重试 |
判断成功的推荐做法:先检查 HTTP 状态码,再检查响应体是否包含 error 字段。
# 全部在线服务器(不排序距离,按人数)
curl "https://scpslserver.com/api.php?sort=players_desc&limit=10"
# 只看中国的模组服,按距离排序
curl "https://scpslserver.com/api.php?ip=223.5.5.5&country=CN&sort=distance_asc"
# 搜索名称含 vanilla 的服务器
curl "https://scpslserver.com/api.php?search=vanilla"
# 某服务器 7 天历史
curl "https://scpslserver.com/history.php?server_id=56351&range=7d"
// 获取离当前访客最近的 20 台服务器
// 浏览器端不传 ip,接口会自动使用访客来源 IP
const res = await fetch('https://scpslserver.com/api.php?sort=distance_asc&limit=20');
const data = await res.json();
if (data.error) {
console.error('请求失败:', data.error);
} else {
console.log(`我的位置: ${data.client.city} (${data.client.precision})`);
data.servers.forEach(s => {
// 注意用 info_text 而非 info,避免 XSS
console.log(`${s.info_text} | ${s.players} | ${s.distance_km} km`);
});
}
// 查询某台服务器的历史人数
const h = await (await fetch(
'https://scpslserver.com/history.php?server_id=56351&range=24h'
)).json();
console.log(`平均 ${h.summary.avg} 人,峰值 ${h.summary.peak} 人`);
<?php
// 传入你自己网站访客的 IP,实现「对该访客就近排序」
$visitorIp = $_SERVER['REMOTE_ADDR'];
$url = 'https://scpslserver.com/api.php?' . http_build_query([
'ip' => $visitorIp,
'sort' => 'distance_asc',
'limit' => 20,
]);
$json = file_get_contents($url);
$data = json_decode($json, true);
if (isset($data['error'])) {
exit('请求失败: ' . $data['error']);
}
foreach ($data['servers'] as $s) {
printf(
"%s | %s | %s km (%s)\n",
$s['info_text'],
$s['players'],
$s['distance_km'] ?? '-',
$s['distance_precision']
);
}
import requests
resp = requests.get('https://scpslserver.com/api.php', params={
'ip': '223.5.5.5',
'sort': 'distance_asc',
'limit': 20,
}, timeout=30)
data = resp.json()
if 'error' in data:
raise RuntimeError(data['error'])
print(f"访客定位: {data['client']['city']} ({data['client']['precision']})")
for s in data['servers']:
print(f"{s['info_text']} | {s['players']} | {s['distance_km']} km")
# 历史人数
h = requests.get('https://scpslserver.com/history.php', params={
'server_id': 56351,
'range': '7d',
}, timeout=30).json()
for p in h['points']:
print(p['ts'], p['avg'], p['peak'])
说明这些服务器的 distance_precision 是 province 或 country——
IP 库对它们只有省级或国家级数据,只能使用同一个参考坐标。可通过该字段识别并在界面上标注为近似值。
不能。上游只提供离线服务器的总数(stats.offline_servers),不提供明细。
离线服务器本身也不响应任何查询协议。
本站的历史数据从部署采集任务的那一刻开始积累。若 collect_since 距今不足 24 小时,
则 7d / 30d 视图自然只有少量数据点。
接口本身可正常访问,但 ip 参数仅支持 IPv4 定位。传入 IPv6 时会无法定位,
distance_km 返回 null,precision 为 unknown。
当前未强制限流。但上游数据 60 秒才更新一次,高频请求没有意义,请将轮询间隔控制在 60 秒以上。
服务器列表完全来自第三方 scplist.kr,本站不修改人数、名称等原始数据,
仅额外做地理定位、距离计算与格式整理。若上游数据有误,本站结果也会一并受影响。