Skip to content

节点与监控

本章覆盖 HyperFRP Panel 后端的节点查询与监控类接口,共 8 个:按地区分组的节点列表(含全局统计)、单节点详情、四类指标历史(CPU / 内存 / 磁盘 / 网络)、四合一聚合历史 metrics,以及 WebRTC 延迟探针的信令中转。

鉴权基调:本章全部 8 个接口都需要登录,通过 Authorization: Bearer <token> 请求头携带 JWT(仅支持请求头方式,不接受 URL 参数传递),Bearer 令牌的获取与使用方式详见认证指南。所有路由经过全站 WAF 防护。缓存差异:节点列表与节点详情为短缓存(ShortCache,响应携带 Cache-Control: public, max-age=60, s-maxage=60),四类历史与 metrics 一律禁止缓存(NoCache,响应携带 Cache-Control: no-store, no-cache, must-revalidate, private),探针中转为 POST 信令、未挂任何缓存中间件。所有接口均返回统一包络 {"code": 0, "message": "...", "data": ...},错误码与 HTTP 状态码对齐;与具体接口无关的通用约定见通用约定

节点列表与详情

GET /api/nodes

返回所有对用户可见的节点,按地区(region)分组,并附带一份面板全局统计(在线节点数、在线用户数、今日流量等)。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:ShortCache(60 秒)

请求示例

bash
curl https://api.hyperfrp.com/api/nodes \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
nodesobject按地区分组的节点集合。键为地区名(管理员配置的 region 字符串,如 华南);region 为空串的节点归入 Overseas 键;值为该地区的 NodeResponse 数组
nodes.*[n].idnumber节点 ID
nodes.*[n].namestring节点名称(唯一)
nodes.*[n].hoststring节点主机地址(域名或 IP)
nodes.*[n].addressstring连接地址,当前与 host 同值(冗余字段)
nodes.*[n].portnumberFRPS 主连接端口
nodes.*[n].locationstring地理位置描述(如 中国 广东 广州
nodes.*[n].descriptionstring节点描述
nodes.*[n].statusstring节点状态,枚举:online / api_only / unreachable / frps_stopped / offline / maintenance
nodes.*[n].clientsOnlinenumber该节点当前在线客户端(FRPC)数
nodes.*[n].proxiesCountnumber该节点上的隧道总数
nodes.*[n].lastHeartbeatstring | null最近一次心跳时间(RFC3339);从未上报时为 null
nodes.*[n].cpuUsagenumberCPU 占用率(百分比数字,如 23.4 表示 23.4%)
nodes.*[n].memoryUsagenumber内存占用率(百分比数字)
nodes.*[n].diskUsagenumber磁盘占用率(百分比数字)
nodes.*[n].networkSpeedInnumber实时入站速度(字节/秒)
nodes.*[n].networkSpeedOutnumber实时出站速度(字节/秒)
nodes.*[n].totalTrafficInBytesnumber节点累计入站流量(字节)
nodes.*[n].totalTrafficOutBytesnumber节点累计出站流量(字节)
nodes.*[n].regionstring地区名,空串时前端应按 Overseas 处理
nodes.*[n].allowedProtocolsstring[]允许的隧道协议类型(如 tcp / udp / http / https);无限制时为空数组 [],不会是 null
nodes.*[n].bandwidthstring带宽描述文本,由数值 + 单位拼接(如 100Mbps1Gbps
nodes.*[n].loadnumber综合负载估算值(0 左右的小数),由隧道估算负载与系统负载加权合成,见注意事项
nodes.*[n].loadAveragestring系统负载原文(如 0.52 0.48 0.45
nodes.*[n].systemLoadstring系统负载 JSON 文本(如 {"load1":0.52,"load5":0.48,"load15":0.45}
nodes.*[n].cpuInfostringCPU 型号描述
nodes.*[n].cpuTemperaturenumberCPU 温度(摄氏度,未上报为 0)
nodes.*[n].quicEnabledboolean是否启用 QUIC 传输
nodes.*[n].isGroupExclusiveboolean是否为用户组专属节点
nodes.*[n].exclusiveTagTextstring专属节点角标文案
nodes.*[n].exclusiveTagColorstring专属节点角标颜色
nodes.*[n].exclusiveTagIconstring专属节点角标图标
nodes.*[n].speedTestPortnumber测速服务端口(0 表示未开启)
nodes.*[n].probeEnabledboolean是否开启 WebRTC 延迟探针
nodes.*[n].probePortnumber延迟探针端口(TCP 信令与 UDP 媒体共用,0 表示未配置)
stats.onlineNodesnumber在线节点数(可见节点中状态为 online / api_only / unreachable 三种均计入)
stats.totalNodesnumber可见节点总数
stats.onlineUsersnumber在线用户数:取「各可见节点在线客户端数之和」与「拥有运行中隧道的去重用户数」二者的较大值
stats.onlineTunnelsnumber在线隧道数(状态为 running 的隧道总数)
stats.todayUploadnumber今日上传流量(字节,自服务器本地时区当日零点起累计)
stats.todayDownloadnumber今日下载流量(字节,统计口径同上)
stats.lastUpdatedstring统计生成时间(RFC3339,服务器本地时区)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": {
    "nodes": {
      "华南": [
        {
          "id": 2,
          "name": "华南-广东-01",
          "host": "gd-01.hyperfrp.com",
          "address": "gd-01.hyperfrp.com",
          "port": 7000,
          "location": "中国 广东 广州",
          "description": "广东电信 BGP 中转节点",
          "status": "online",
          "clientsOnline": 12,
          "proxiesCount": 34,
          "lastHeartbeat": "2026-09-19T22:58:31+08:00",
          "cpuUsage": 23.4,
          "memoryUsage": 61.8,
          "diskUsage": 42.1,
          "networkSpeedIn": 1048576,
          "networkSpeedOut": 2097152,
          "totalTrafficInBytes": 182536110080,
          "totalTrafficOutBytes": 365072220160,
          "region": "华南",
          "allowedProtocols": ["tcp", "udp", "http", "https"],
          "bandwidth": "100Mbps",
          "load": 0.49,
          "loadAverage": "0.52 0.48 0.45",
          "systemLoad": "{\"load1\":0.52,\"load5\":0.48,\"load15\":0.45}",
          "cpuInfo": "Intel Xeon Platinum 8269CY",
          "cpuTemperature": 45.5,
          "quicEnabled": true,
          "isGroupExclusive": false,
          "exclusiveTagText": "",
          "exclusiveTagColor": "#ff69b4",
          "exclusiveTagIcon": "",
          "speedTestPort": 27000,
          "probeEnabled": true,
          "probePort": 27100
        }
      ],
      "Overseas": [
        {
          "id": 1,
          "name": "HK-01",
          "host": "hk-01.hyperfrp.com",
          "address": "hk-01.hyperfrp.com",
          "port": 7000,
          "location": "中国 香港",
          "description": "",
          "status": "online",
          "clientsOnline": 5,
          "proxiesCount": 18,
          "lastHeartbeat": "2026-09-19T22:58:02+08:00",
          "cpuUsage": 11.2,
          "memoryUsage": 43.6,
          "diskUsage": 28.9,
          "networkSpeedIn": 524288,
          "networkSpeedOut": 262144,
          "totalTrafficInBytes": 107374182400,
          "totalTrafficOutBytes": 214748364800,
          "region": "",
          "allowedProtocols": [],
          "bandwidth": "30Mbps",
          "load": 0.21,
          "loadAverage": "0.10 0.12 0.11",
          "systemLoad": "",
          "cpuInfo": "AMD EPYC 7K62",
          "cpuTemperature": 0,
          "quicEnabled": false,
          "isGroupExclusive": false,
          "exclusiveTagText": "",
          "exclusiveTagColor": "#ff69b4",
          "exclusiveTagIcon": "",
          "speedTestPort": 0,
          "probeEnabled": false,
          "probePort": 0
        }
      ]
    },
    "stats": {
      "onlineNodes": 2,
      "totalNodes": 2,
      "onlineUsers": 15,
      "onlineTunnels": 52,
      "todayUpload": 5368709120,
      "todayDownload": 10737418240,
      "lastUpdated": "2026-09-19T23:01:44+08:00"
    }
  }
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截,见认证指南
节点列表查询失败(数据库异常)500获取节点列表失败

注意事项

  • 仅返回 is_visible = true 的节点,按节点名称升序排列;隐藏节点对本接口完全不可见。
  • load 为服务端合成的估算负载:隧道估算负载 × 0.8 + 系统负载 × 0.2,其中隧道估算负载 = (proxiesCount × 2) / 带宽MbpsGbps 单位会先换算为 Mbps),系统负载取 loadAverage 的首个数值;两者皆缺失时为 0。
  • stats.todayUpload / stats.todayDownload 是「流量历史记录」按当日零点汇总的字节数,不是实时速率;实时速率见各节点的 networkSpeedIn / networkSpeedOut
  • 响应缓存 60 秒(max-age=60),刚刚上线的节点或状态跃迁最多延迟 1 分钟可见。

GET /api/nodes/:id

返回单个节点的完整配置与运行状态,即原始 Node 模型的 JSON 序列化结果(含 FRPS 配置参数)。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:ShortCache(60 秒)

请求示例

bash
curl https://api.hyperfrp.com/api/nodes/2 \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

data 为原始 Node 模型。凭证类字段(tokenhyperzonefrpApiTokenhyperzonefrpNodeTokendashboardUserdashboardPassword)在模型上标记为 json:"-"响应中不会出现。另有若干非数据库字段(memoryTotalmemoryUseddiskTotaldiskUsedlogPathfrpsPathconfigPath)本接口不做填充,恒为 0 或空串。

识别与展示

字段类型说明
idnumber节点 ID
namestring节点名称(唯一)
hoststring节点主机地址
domainstring节点域名(可为空串)
locationstring地理位置
descriptionstring节点描述
regionstring地区名,默认 Overseas
statusstring节点状态,枚举:online / api_only / unreachable / frps_stopped / offline / maintenance
isVisibleboolean是否对用户可见(不可见节点无法通过本接口查询到)
lastHeartbeatstring | null最近心跳时间(RFC3339)
onlineSincestring | null本次上线起始时间(RFC3339)
bootTimenumber | null节点系统启动时间戳(秒)
createdAtstring创建时间(RFC3339)
updatedAtstring更新时间(RFC3339)

接入与端口

字段类型说明
portnumberFRPS 主连接端口
bindAddressstring监听地址,默认 0.0.0.0
kcpBindPortnumberKCP 传输端口(0 = 未启用)
quicEnabledboolean是否启用 QUIC
quicBindPortnumberQUIC 端口
vhostHTTPPortnumberHTTP 虚拟主机端口
vhostHTTPSPortnumberHTTPS 虚拟主机端口
dashboardPortnumberFRPS Dashboard 端口
webServerAddrstringDashboard 监听地址,默认 127.0.0.1
tcpMuxboolean是否启用 TCP 复用
tcpMuxHTTPConnectPortnumberTCP 复用 HTTP CONNECT 端口
tcpKeepAlivenumberTCP Keep-Alive 探测间隔(秒)
heartbeatTimeoutnumber心跳超时(秒),默认 90
maxPoolCountnumber客户端连接池上限,默认 5
tlsForceboolean是否强制 TLS
speedTestPortnumber测速服务端口(0 = 未开启)
probeEnabledboolean是否开启 WebRTC 延迟探针
probePortnumber探针端口(TCP 信令与 UDP 媒体共用)

资源与监控

字段类型说明
cpuInfostringCPU 型号
cpuTemperaturenumberCPU 温度(摄氏度)
cpuUsagenumberCPU 占用率(百分比数字)
loadAveragestring系统负载原文
systemLoadstring系统负载 JSON 文本
memoryUsagenumber内存占用率(百分比数字)
memoryTotalnumber内存总量(字节);本接口恒为 0(非库字段,未填充)
memoryUsednumber已用内存(字节);本接口恒为 0
diskUsagenumber磁盘占用率(百分比数字)
diskTotalnumber磁盘总量(字节);本接口恒为 0
diskUsednumber已用磁盘(字节);本接口恒为 0
networkSpeedInnumber实时入站速度(字节/秒)
networkSpeedOutnumber实时出站速度(字节/秒)
clientsOnlinenumber在线客户端数
proxiesCountnumber隧道总数

流量与限额

字段类型说明
totalTrafficInBytesnumber累计入站流量(字节)
totalTrafficOutBytesnumber累计出站流量(字节)
frpsReportedInBytesnumberFRPS 最近一次上报的累计入站字节数(用于增量对账)
frpsReportedOutBytesnumberFRPS 最近一次上报的累计出站字节数
networkPacketsSentnumber网络发包计数(当前上报恒为 0)
networkPacketsRecvnumber网络收包计数(当前上报恒为 0)
maxProxiesnumber单用户隧道数上限,默认 10
bandwidthLimitKbpsnumber单隧道带宽限制(Kbps),默认 10240
bandwidthValuenumber节点带宽数值,默认 100
bandwidthUnitstring带宽单位,枚举:Mbps / Gbps

准入控制

字段类型说明
allowedGroupIdsnumber[]允许访问的用户组 ID 列表;空数组表示不限
isGroupExclusiveboolean是否为用户组专属节点
permissionMessagestring无权限时展示的提示文案
exclusiveTagTextstring专属角标文案
exclusiveTagColorstring专属角标颜色,默认 #ff69b4
exclusiveTagIconstring专属角标图标
allowedPortsStartnumber单段端口范围起点(0 = 不限)
allowedPortsEndnumber单段端口范围终点
allowPortRangesobject[]多段端口范围数组,元素为 {"start": number, "end": number};非空时优先生效
allowedProtocolsstring[]允许的隧道协议类型;空数组表示按默认策略

HyperzoneFRP 联动

字段类型说明
hyperzonefrpApiURLstring节点回连面板的 API 基址
hyperzonefrpHeartbeatIntervalnumber节点心跳上报间隔(秒),默认 30
hyperzonefrpResourceIntervalnumber节点资源上报间隔(秒),默认 15
hyperzonefrpTrafficFlushIntervalnumber节点流量冲账间隔(秒),默认 10
hyperzonefrpTunnelCheckIntervalnumber节点隧道巡检间隔(秒),默认 30
trafficQueuePathstring流量 WAL 路径(空串表示使用面板安全默认)
trafficQueueHighWatermarknumber流量队列高水位(条数),默认 10000
upgradeEnabledboolean自动升级总开关,默认 false
panelFailureModestring面板不可用降级策略,枚举:fail-closed / fail-open
upgradeServiceNamestring升级器服务名
upgradeInstallDirstring升级器安装目录
upgradeSelfCheckWindownumber升级自检窗口(秒),默认 60

日志与其他

字段类型说明
logLevelstringFRPS 日志级别,默认 info
logMaxDaysnumberFRPS 日志保留天数,默认 7
disableLogColorboolean是否禁用日志颜色
logPathstring日志路径;本接口恒为空串(非库字段,未填充)
frpsPathstringFRPS 程序路径;本接口恒为空串
configPathstringFRPS 配置路径;本接口恒为空串

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": {
    "id": 2,
    "name": "华南-广东-01",
    "host": "gd-01.hyperfrp.com",
    "domain": "gd-01.hyperfrp.com",
    "port": 7000,
    "bindAddress": "0.0.0.0",
    "kcpBindPort": 0,
    "quicEnabled": true,
    "quicBindPort": 7001,
    "vhostHTTPPort": 8080,
    "vhostHTTPSPort": 8443,
    "speedTestPort": 27000,
    "probeEnabled": true,
    "probePort": 27100,
    "allowedGroupIds": [1, 3],
    "isGroupExclusive": false,
    "permissionMessage": "",
    "exclusiveTagText": "",
    "exclusiveTagColor": "#ff69b4",
    "exclusiveTagIcon": "",
    "allowedPortsStart": 10000,
    "allowedPortsEnd": 65535,
    "allowPortRanges": [],
    "location": "中国 广东 广州",
    "description": "广东电信 BGP 中转节点",
    "status": "online",
    "cpuInfo": "Intel Xeon Platinum 8269CY",
    "cpuTemperature": 45.5,
    "isVisible": true,
    "maxProxies": 20,
    "bandwidthLimitKbps": 10240,
    "totalTrafficInBytes": 182536110080,
    "totalTrafficOutBytes": 365072220160,
    "networkPacketsSent": 0,
    "networkPacketsRecv": 0,
    "clientsOnline": 12,
    "proxiesCount": 34,
    "lastHeartbeat": "2026-09-19T22:58:31+08:00",
    "onlineSince": "2026-09-18T08:12:00+08:00",
    "bootTime": 1758200000,
    "cpuUsage": 23.4,
    "loadAverage": "0.52 0.48 0.45",
    "systemLoad": "{\"load1\":0.52,\"load5\":0.48,\"load15\":0.45}",
    "memoryUsage": 61.8,
    "memoryTotal": 0,
    "memoryUsed": 0,
    "diskUsage": 42.1,
    "diskTotal": 0,
    "diskUsed": 0,
    "networkSpeedIn": 1048576,
    "networkSpeedOut": 2097152,
    "frpsReportedInBytes": 182536110080,
    "frpsReportedOutBytes": 365072220160,
    "logPath": "",
    "frpsPath": "",
    "configPath": "",
    "dashboardPort": 7500,
    "webServerAddr": "127.0.0.1",
    "tcpMux": true,
    "tcpMuxHTTPConnectPort": 0,
    "tcpKeepAlive": 7200,
    "heartbeatTimeout": 90,
    "maxPoolCount": 5,
    "tlsForce": false,
    "logLevel": "info",
    "logMaxDays": 7,
    "disableLogColor": false,
    "region": "华南",
    "allowedProtocols": ["tcp", "udp", "http", "https"],
    "bandwidthValue": 100,
    "bandwidthUnit": "Mbps",
    "hyperzonefrpApiURL": "https://api.hyperfrp.com/api",
    "hyperzonefrpHeartbeatInterval": 30,
    "hyperzonefrpResourceInterval": 15,
    "hyperzonefrpTrafficFlushInterval": 10,
    "hyperzonefrpTunnelCheckInterval": 30,
    "trafficQueuePath": "",
    "trafficQueueHighWatermark": 10000,
    "upgradeEnabled": false,
    "panelFailureMode": "fail-closed",
    "upgradeServiceName": "",
    "upgradeInstallDir": "",
    "upgradeSelfCheckWindow": 60,
    "createdAt": "2026-06-01T10:00:00+08:00",
    "updatedAt": "2026-09-19T22:58:31+08:00"
  }
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在,或存在但对用户不可见(is_visible = false404节点未找到

历史监控

四个单指标历史端点与聚合端点 metrics 同构:数据来自节点资源上报写入的 node_metric_histories 表,按时间桶聚合(桶内取均值)。时间范围二选一:提供 startDate + endDate 时按日期区间查询;否则按 interval 决定(hour = 近 24 小时按小时聚合;缺省或其他任意值 = 近 30 天按天聚合)。

GET /api/nodes/:id/cpu-history

返回节点 CPU 占用率的历史曲线,元素为 {time, value}

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:NoCache

查询参数

参数类型必填说明
intervalstringhour:近 24 小时、按小时聚合;缺省或其他任意值:近 30 天、按天聚合
startDatestring起始日期,格式 YYYY-MM-DD;与 endDate 同时提供时生效,并优先于 interval
endDatestring结束日期,格式 YYYY-MM-DD;聚合时结束日期向后扩展 24 小时(即含 endDate 当天全天)

请求示例

bash
curl "https://api.hyperfrp.com/api/nodes/2/cpu-history?interval=hour" \
  -H "Authorization: Bearer <token>"

# 按日期区间查询
curl "https://api.hyperfrp.com/api/nodes/2/cpu-history?startDate=2026-09-01&endDate=2026-09-19" \
  -H "Authorization: Bearer <token>"
javascript
// 按日期区间查询:GET /api/nodes/2/cpu-history?startDate=2026-09-01&endDate=2026-09-19
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/cpu-history?interval=hour', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

# 按日期区间查询:GET /api/nodes/2/cpu-history?startDate=2026-09-01&endDate=2026-09-19
res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2/cpu-history?interval=hour',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
// 按日期区间查询:GET /api/nodes/2/cpu-history?startDate=2026-09-01&endDate=2026-09-19
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2/cpu-history?interval=hour", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
[n].timestring时间桶标签:interval=hour 时为 YYYY-MM-DD HH:00;按天聚合时为 YYYY-MM-DD
[n].valuenumber该时间桶内 CPU 占用率均值(百分比数字,0~100)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": [
    { "time": "2026-09-19 14:00", "value": 23.4 },
    { "time": "2026-09-19 15:00", "value": 31.2 },
    { "time": "2026-09-19 16:00", "value": 18.7 }
  ]
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在 / 不可见 / 无历史数据200返回空数组 []不报 404

注意事项

  • startDate / endDate 仅在两者同时提供且格式合法时生效,否则回落到 interval 逻辑。
  • 返回数组的顺序不保证按时间升序(聚合按分组结果遍历),绘制曲线前请先按 time 排序。

GET /api/nodes/:id/memory-history

返回节点内存占用率的历史曲线,结构与 cpu-history 完全一致。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:NoCache

查询参数

参数类型必填说明
intervalstringhour:近 24 小时、按小时聚合;缺省或其他任意值:近 30 天、按天聚合
startDatestring起始日期,格式 YYYY-MM-DD;与 endDate 同时提供时生效并优先于 interval
endDatestring结束日期,格式 YYYY-MM-DD,含当天全天

请求示例

bash
curl "https://api.hyperfrp.com/api/nodes/2/memory-history?interval=hour" \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/memory-history?interval=hour', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2/memory-history?interval=hour',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2/memory-history?interval=hour", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
[n].timestring时间桶标签,格式同 cpu-history
[n].valuenumber该时间桶内内存占用率均值(百分比数字,0~100)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": [
    { "time": "2026-09-19 14:00", "value": 61.8 },
    { "time": "2026-09-19 15:00", "value": 63.1 }
  ]
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在 / 不可见 / 无历史数据200返回空数组 []不报 404

注意事项

  • 返回数组顺序不保证按时间升序,绘制前请按 time 排序。

GET /api/nodes/:id/disk-history

返回节点磁盘占用率的历史曲线,结构与 cpu-history 完全一致。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:NoCache

查询参数

参数类型必填说明
intervalstringhour:近 24 小时、按小时聚合;缺省或其他任意值:近 30 天、按天聚合
startDatestring起始日期,格式 YYYY-MM-DD;与 endDate 同时提供时生效并优先于 interval
endDatestring结束日期,格式 YYYY-MM-DD,含当天全天

请求示例

bash
curl "https://api.hyperfrp.com/api/nodes/2/disk-history?startDate=2026-09-01&endDate=2026-09-19" \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/disk-history?startDate=2026-09-01&endDate=2026-09-19', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2/disk-history?startDate=2026-09-01&endDate=2026-09-19',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2/disk-history?startDate=2026-09-01&endDate=2026-09-19", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
[n].timestring时间桶标签,格式同 cpu-history
[n].valuenumber该时间桶内磁盘占用率均值(百分比数字,0~100)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": [
    { "time": "2026-09-18", "value": 41.9 },
    { "time": "2026-09-19", "value": 42.1 }
  ]
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在 / 不可见 / 无历史数据200返回空数组 []不报 404

注意事项

  • 返回数组顺序不保证按时间升序,绘制前请按 time 排序。

GET /api/nodes/:id/network-history

返回节点网络速率的历史曲线。每个时间桶产出两条记录(入站 / 出站各一条),通过 type 字段区分。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:NoCache

查询参数

参数类型必填说明
intervalstringhour:近 24 小时、按小时聚合;缺省或其他任意值:近 30 天、按天聚合
startDatestring起始日期,格式 YYYY-MM-DD;与 endDate 同时提供时生效并优先于 interval
endDatestring结束日期,格式 YYYY-MM-DD,含当天全天

请求示例

bash
curl "https://api.hyperfrp.com/api/nodes/2/network-history?interval=hour" \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/network-history?interval=hour', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2/network-history?interval=hour',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2/network-history?interval=hour", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
[n].timestring时间桶标签,格式同 cpu-history
[n].valuenumber该时间桶内网络速率均值(字节/秒)
[n].typestring曲线类别,固定两个值:入站速度(对应 networkSpeedIn 均值)与 出站速度(对应 networkSpeedOut 均值)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": [
    { "time": "2026-09-19 14:00", "value": 1048576, "type": "入站速度" },
    { "time": "2026-09-19 14:00", "value": 2097152, "type": "出站速度" },
    { "time": "2026-09-19 15:00", "value": 786432, "type": "入站速度" },
    { "time": "2026-09-19 15:00", "value": 1572864, "type": "出站速度" }
  ]
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在 / 不可见 / 无历史数据200返回空数组 []不报 404

注意事项

  • 每个时间桶固定产出 入站速度 + 出站速度 两条记录,数组长度约为时间桶数的 2 倍。
  • type 取值为中文字面量 入站速度 / 出站速度,前端按该字符串分组曲线。
  • 返回数组顺序不保证按时间升序,绘制前请按 time 排序。

GET /api/nodes/:id/metrics

一次请求返回四类指标的聚合历史(CPU / 内存 / 磁盘 / 网络双向),字段名为 snake_case。本端点不支持 startDate / endDate,仅按 interval 取时间窗。

鉴权:JWT Bearer · 限流:无专用限流(WAF 全局策略照常生效) · 缓存:NoCache

查询参数

参数类型必填说明
intervalstringhour:近 24 小时、按小时聚合;缺省(服务端置为 day)或其他值:近 30 天、按天聚合

请求示例

bash
curl "https://api.hyperfrp.com/api/nodes/2/metrics?interval=hour" \
  -H "Authorization: Bearer <token>"
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/metrics?interval=hour', {
  headers: {
    'Authorization': 'Bearer <token>',
  },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    'https://api.hyperfrp.com/api/nodes/2/metrics?interval=hour',
    headers={'Authorization': 'Bearer <token>'},
)
data = res.json()
print(data)
go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.hyperfrp.com/api/nodes/2/metrics?interval=hour", nil)
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
[n].timestring时间桶标签:interval=hour 时为 YYYY-MM-DD HH:00;按天聚合时为 YYYY-MM-DD
[n].cpu_usagenumber该时间桶内 CPU 占用率均值(百分比数字,0~100)
[n].memory_usagenumber该时间桶内内存占用率均值(百分比数字,0~100)
[n].disk_usagenumber该时间桶内磁盘占用率均值(百分比数字,0~100)
[n].network_innumber该时间桶内入站速率均值(字节/秒)
[n].network_outnumber该时间桶内出站速率均值(字节/秒)

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": [
    {
      "time": "2026-09-19 14:00",
      "cpu_usage": 23.4,
      "memory_usage": 61.8,
      "disk_usage": 42.1,
      "network_in": 1048576,
      "network_out": 2097152
    },
    {
      "time": "2026-09-19 15:00",
      "cpu_usage": 31.2,
      "memory_usage": 63.1,
      "disk_usage": 42.1,
      "network_in": 786432,
      "network_out": 1572864
    }
  ]
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
节点不存在 / 不可见 / 无历史数据200返回空数组 []不报 404

注意事项

  • 字段名与其他历史端点不同:本端点为 snake_case(cpu_usage 等),其余端点为驼峰 / 小写(cpuUsagevalue),对接时注意区分。
  • 百分比字段是 0~100 的数字而非带 % 的字符串;网络字段单位是字节/秒。
  • 返回数组顺序不保证按时间升序,绘制前请按 time 排序。

延迟探测

POST /api/nodes/:id/probe

WebRTC 延迟探针的信令中转:浏览器把本地 SDP offer 提交给面板(同源 HTTPS),面板用节点的联动密钥签发一次性 proof 后转发到节点探针端口,再把节点返回的 answer SDP 原样回传;浏览器据此与节点直连建立 DataChannel,测量真实 RTT。

鉴权:JWT Bearer · 限流:每用户令牌桶 20 次/分钟(容量 20、匀速补充,超出返回 429) · 缓存:无(路由未挂缓存中间件)

请求体

字段类型必填说明
sdpstring浏览器本地 RTCPeerConnection 生成的 SDP offer 全文;非空且不超过 16384 字节(16 KiB)

请求示例

bash
curl -X POST https://api.hyperfrp.com/api/nodes/2/probe \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"sdp":"v=0\r\no=- 4611731395439611998 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=ice-ufrag:4ZcD\r\na=ice-pwd:2/1muCXRGhNyMM5uMpuP9YLHy\r\n..."}'
javascript
const res = await fetch('https://api.hyperfrp.com/api/nodes/2/probe', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer <token>',
  },
  body: JSON.stringify({"sdp":"v=0\r\no=- 4611731395439611998 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=ice-ufrag:4ZcD\r\na=ice-pwd:2/1muCXRGhNyMM5uMpuP9YLHy\r\n..."})
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.post(
    'https://api.hyperfrp.com/api/nodes/2/probe',
    headers={'Authorization': 'Bearer <token>'},
    json={
        'sdp': 'v=0
o=- 4611731395439611998 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=ice-ufrag:4ZcD
a=ice-pwd:2/1muCXRGhNyMM5uMpuP9YLHy
...'
    },
)
data = res.json()
print(data)
go
package main

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

func main() {
	var payload bytes.Buffer
	json.NewEncoder(&payload).Encode(map[string]any{
		"sdp": "v=0\r\no=- 4611731395439611998 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=ice-ufrag:4ZcD\r\na=ice-pwd:2/1muCXRGhNyMM5uMpuP9YLHy\r\n...",
	})

	req, _ := http.NewRequest("POST", "https://api.hyperfrp.com/api/nodes/2/probe", &payload)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer <token>")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var result map[string]any
	json.NewDecoder(res.Body).Decode(&result)
	fmt.Println(result)
}

响应字段

字段类型说明
sdpstring节点返回的 SDP answer 全文,面板原样透传不做解析

响应示例

json
{
  "code": 0,
  "message": "成功",
  "data": {
    "sdp": "v=0\r\no=- 4611731409170018437 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=ice-ufrag:8Km2\r\na=ice-pwd:xJ9pQ2wRvN5tYbCd3eFgHi\r\n..."
  }
}

错误场景

场景HTTP说明
JWT 缺失 / 无效 / 会话失效401由鉴权中间件统一拦截
当前用户令牌桶耗尽(超过 20 次/分钟)429延迟探测过于频繁,请稍候
节点不存在 / 不可见404节点未找到
节点未开启探测(probeEnabled = falseprobePort <= 0400该节点未开启延迟探测
请求体缺失 / 非法 JSON / sdp 为空400缺少 sdp
sdp 超过 16384 字节400sdp 过大
面板无法连上节点探针端口(含 8 秒转发超时)400节点探测端口不可达
节点拒绝本次探测 offer400节点拒绝探测请求(<HTTP状态码>)
节点探测侧自身限流(返回 429)429节点探测繁忙,请稍后重试
节点应答解析失败或 answer 为空400节点返回的 answer 无效
节点缺少面板联动密钥,无法签发探测凭证500节点缺少面板联动密钥,无法签发探测凭证
服务端生成随机 nonce 失败500生成 nonce 失败

注意事项

  • 为什么必须经面板同源中转:控制台页面运行在 HTTPS 下,节点探针端口是节点侧的裸 HTTP 服务,浏览器直接请求属于混合内容,会被整段拦截;同时浏览器也无法自行签发节点认得的凭证。面板作为受信中继,使用面板持有的节点联动密钥签发探测凭证,该密钥从不下发给浏览器;浏览器只提交 SDP,收到 answer 后与节点直连测真实 RTT。
  • 一次性防伪:面板为每次转发签发一次性探测凭证发往节点,节点校验通过后仅应答一次,重放无效;凭证签发细节不对外公开。
  • 限流先于节点校验执行:按用户维度计,刚触发限流时响应与节点侧限流同为 429,按 message 区分即可。
  • 探测端点不可达、节点拒绝等转发失败统一以 400 返回(节点侧 429 除外),SDP 本身超限(16 KiB)也会被 400 拒绝;浏览器侧生成 offer 时无需控制候选数量,但过大仍会被拒。

本站基于 VitePress 构建,文档内容以 backend-Go handler 源码为权威依据