Files
Archive/nodepass/docs/zh/api.md
2025-09-06 20:35:55 +02:00

1138 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NodePass API 参考
## 概述
NodePass 主控模式Master Mode下提供 RESTful API支持前端集成和自动化。本文档涵盖所有接口、数据结构和最佳实践。
## 主控模式 API
主控模式(`master://`NodePass 支持:
1. 创建和管理服务端/客户端实例
2. 实时监控状态、流量、健康检查
3. 控制实例(启动、停止、重启、重置流量)
4. 配置自启动策略
5. 灵活参数配置
### 基础 URL
```
master://<api_addr>/<prefix>?<log>&<tls>
```
- `<api_addr>`:监听地址(如 `0.0.0.0:9090`
- `<prefix>`API 路径前缀(默认 `/api`
### 启动主控模式
```bash
nodepass "master://0.0.0.0:9090?log=info"
nodepass "master://0.0.0.0:9090/admin?log=info&tls=1"
```
### 主要接口
| Endpoint | Method | 说明 |
|--------------------|--------|----------------------|
| `/instances` | GET | 获取所有实例 |
| `/instances` | POST | 创建新实例 |
| `/instances/{id}` | GET | 获取实例详情 |
| `/instances/{id}` | PATCH | 更新/控制实例 |
| `/instances/{id}` | PUT | 更新实例 URL |
| `/instances/{id}` | DELETE | 删除实例 |
| `/events` | GET | SSE 实时事件流 |
| `/info` | GET | 获取主控服务信息 |
| `/tcping` | GET | TCP连接测试 |
| `/openapi.json` | GET | OpenAPI 规范 |
| `/docs` | GET | Swagger UI 文档 |
### API 鉴权
API Key 认证默认启用,首次启动自动生成并保存在 `nodepass.gob`
- 受保护接口:`/instances``/instances/{id}``/events``/info``/tcping`
- 公共接口:`/openapi.json``/docs`
- 认证方式:请求头加 `X-API-Key: <key>`
- 重置 KeyPATCH `/instances/********`body `{ "action": "restart" }`
### 实例数据结构
```json
{
"id": "a1b2c3d4",
"alias": "别名",
"type": "client|server",
"status": "running|stopped|error",
"url": "...",
"restart": true,
"mode": 0,
"ping": 0,
"pool": 0,
"tcps": 0,
"udps": 0,
"tcprx": 0,
"tcptx": 0,
"udprx": 0,
"udptx": 0
}
```
- `mode`:实例运行模式
- `ping`/`pool`:健康检查数据
- `tcps`/`udps`:当前活动连接数统计
- `tcprx`/`tcptx`/`udprx`/`udptx`:累计流量统计
- `restart`:自启动策略
### 实例 URL 格式
- 服务端:`server://<bind_addr>:<bind_port>/<target_host>:<target_port>?<参数>`
- 客户端:`client://<server_host>:<server_port>/<local_host>:<local_port>?<参数>`
- 支持参数:`log``tls``crt``key``min``max``mode``read``rate`
### URL 查询参数
- `log`:日志级别(`none``debug``info``warn``error``event`
- `tls`TLS加密模式`0``1``2`- 仅服务端/主控模式
- `crt`/`key`:证书/密钥文件路径(当`tls=2`时)
- `min`/`max`:连接池容量(`min`由客户端设置,`max`由服务端设置并在握手时传递给客户端)
- `mode`:运行模式控制(`0``1``2`- 控制操作行为
- 对于服务端:`0`=自动,`1`=反向模式,`2`=正向模式
- 对于客户端:`0`=自动,`1`=单端转发,`2`=双端握手
- `read`数据读取超时时长如1h、30m、15s
- `rate`带宽速率限制单位Mbps0=无限制)
- `proxy`PROXY协议支持`0``1`- 启用后在数据传输前发送PROXY协议v1头部
### 实时事件流SSE
- 事件类型:`initial``create``update``delete``shutdown``log`
- `log` 事件仅推送普通日志,流量/健康检查日志已被过滤
- 连接 `/events` 可实时获取实例变更和日志
### 其他说明
- 所有实例、流量、健康检查、别名、自启动策略均持久化存储,重启后自动恢复
- API 详细规范见 `/openapi.json`Swagger UI 见 `/docs`
```javascript
// 重新生成API Key需要知道当前的API Key
async function regenerateApiKey() {
const response = await fetch(`${API_URL}/instances/${apiKeyID}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'current-api-key'
},
body: JSON.stringify({ action: 'restart' })
});
const result = await response.json();
return result.url; // 新的API Key
}
```
**注意**: API Key ID 固定为 `********`八个星号。在内部实现中这是一个特殊的实例ID用于存储和管理API Key。
### 使用SSE实时事件监控
NodePass现在支持服务器发送事件(SSE)功能,用于实时监控实例状态变化。这使前端应用能够即时接收实例创建、更新和删除的通知,无需轮询。
#### 使用SSE端点
SSE端点位于
```
GET /events
```
此端点建立持久连接使用SSE协议格式实时传递事件。如果启用了API Key认证需要在请求头中包含有效的API Key。
#### 事件类型
支持以下事件类型:
1. `initial` - 连接建立时发送,包含所有实例的当前状态
2. `create` - 创建新实例时发送
3. `update` - 实例更新时发送(状态变更、启动/停止操作)
4. `delete` - 实例被删除时发送
5. `shutdown` - 主控服务即将关闭时发送,通知前端应用关闭连接
6. `log` - 实例产生新日志内容时发送,包含日志文本
#### 处理实例日志
在前端应用中,可以通过监听`log`事件来处理实例日志。以下是一个示例函数用于将日志追加到特定实例的UI中
```javascript
// 处理日志事件
function appendLogToInstanceUI(instanceId, logText) {
// 找到或创建日志容器
let logContainer = document.getElementById(`logs-${instanceId}`);
if (!logContainer) {
logContainer = document.createElement('div');
logContainer.id = `logs-${instanceId}`;
document.getElementById('instance-container').appendChild(logContainer);
}
// 创建新的日志条目
const logEntry = document.createElement('div');
logEntry.className = 'log-entry';
// 可以在这里解析ANSI颜色代码或格式化日志
logEntry.textContent = logText;
// 添加到容器
logContainer.appendChild(logEntry);
// 滚动到最新日志
logContainer.scrollTop = logContainer.scrollHeight;
}
```
日志集成最佳实践:
1. **缓冲管理**:限制日志条目的数量,以防止内存问题
2. **ANSI颜色解析**解析日志中的ANSI颜色代码以提高可读性
3. **过滤选项**:提供按严重性或内容过滤日志的选项
4. **搜索功能**:允许用户在实例日志中搜索
5. **日志持久化**:可选地将日志保存到本地存储,以便在页面刷新后查看
#### JavaScript客户端实现
以下是JavaScript前端消费SSE端点的示例
```javascript
function connectToEventSource() {
const eventSource = new EventSource(`${API_URL}/events`, {
// 如果需要认证原生EventSource不支持自定义请求头
// 需要使用fetch API实现自定义SSE客户端
});
// 如果使用API Key需要使用自定义实现代替原生EventSource
// 下面是使用原生EventSource的示例
eventSource.addEventListener('instance', (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'initial':
console.log('初始实例状态:', data.instance);
updateInstanceUI(data.instance);
break;
case 'create':
console.log('实例已创建:', data.instance);
addInstanceToUI(data.instance);
break;
case 'update':
console.log('实例已更新:', data.instance);
updateInstanceUI(data.instance);
break;
case 'delete':
console.log('实例已删除:', data.instance);
removeInstanceFromUI(data.instance.id);
break;
case 'log':
console.log(`实例 ${data.instance.id} 日志:`, data.logs);
appendLogToInstanceUI(data.instance.id, data.logs);
break;
case 'shutdown':
console.log('主控服务即将关闭');
// 关闭事件源并显示通知
eventSource.close();
showShutdownNotification();
break;
}
});
eventSource.addEventListener('error', (error) => {
console.error('SSE连接错误:', error);
// 延迟后尝试重新连接
setTimeout(() => {
eventSource.close();
connectToEventSource();
}, 5000);
});
return eventSource;
}
// 使用API Key创建SSE连接的示例
function connectToEventSourceWithApiKey(apiKey) {
// 原生EventSource不支持自定义请求头需要使用fetch API
fetch(`${API_URL}/events`, {
method: 'GET',
headers: {
'X-API-Key': apiKey,
'Cache-Control': 'no-cache'
}
}).then(response => {
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
function processStream() {
reader.read().then(({ value, done }) => {
if (done) {
console.log('连接已关闭');
// 尝试重新连接
setTimeout(() => connectToEventSourceWithApiKey(apiKey), 5000);
return;
}
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.trim() === '') continue;
const eventMatch = line.match(/^event: (.+)$/m);
const dataMatch = line.match(/^data: (.+)$/m);
if (eventMatch && dataMatch) {
const data = JSON.parse(dataMatch[1]);
// 处理事件 - 见上面的switch代码
}
}
processStream();
}).catch(error => {
console.error('读取错误:', error);
// 尝试重新连接
setTimeout(() => connectToEventSourceWithApiKey(apiKey), 5000);
});
}
processStream();
}).catch(error => {
console.error('连接错误:', error);
// 尝试重新连接
setTimeout(() => connectToEventSourceWithApiKey(apiKey), 5000);
});
}
```
#### SSE相比轮询的优势
使用SSE监控实例状态比传统轮询提供多种优势
1. **减少延迟**:变更实时传递
2. **减轻服务器负载**:消除不必要的轮询请求
3. **带宽效率**:只在发生变更时发送数据
4. **原生浏览器支持**:无需额外库的内置浏览器支持
5. **自动重连**:浏览器在连接丢失时自动重连
#### SSE实现的最佳实践
在前端实现SSE时
1. **处理重连**:虽然浏览器会自动尝试重连,但应实现自定义逻辑以确保持久连接
2. **高效处理事件**保持事件处理快速避免UI阻塞
3. **实现回退机制**在不支持SSE的环境中实现轮询回退
4. **处理错误**:正确处理连接错误和断开
5. **日志管理**:为每个实例维护日志缓冲区,避免无限制增长
## 前端集成指南
在将NodePass与前端应用集成时请考虑以下重要事项
### 实例持久化
NodePass主控模式现在支持使用gob序列化格式进行实例持久化。实例及其状态会保存到与可执行文件相同目录下的`nodepass.gob`文件中,并在主控重启时自动恢复。
主要持久化特性:
- 实例配置自动保存到磁盘
- 实例状态(运行/停止)得到保留
- 自启动策略在主控重启间保持不变
- 流量统计数据在重启之间保持
- 启用自启动策略的实例在主控重启时自动启动
- 重启后无需手动重新注册
#### 自动备份功能
NodePass主控模式提供自动备份功能定期备份状态文件以防止数据丢失
- **备份文件**:自动创建 `nodepass.gob.backup` 备份文件
- **备份周期**每1小时自动备份一次可通过环境变量 `NP_RELOAD_INTERVAL` 配置)
- **备份策略**:使用单一备份文件,新备份会覆盖旧备份
- **备份内容**:包含所有实例配置、状态、自启动策略和统计数据
- **故障恢复**:当主文件损坏时,可手动使用备份文件恢复
- **自动启动**:备份功能随主控服务自动启动,无需额外配置
备份文件位置:与主状态文件 `nodepass.gob` 相同目录下的 `nodepass.gob.backup`
**注意:** 虽然实例配置现在已经持久化并自动备份,前端应用仍应保留自己的实例配置记录作为额外的备份策略。
### 实例生命周期管理
为了合理管理生命周期:
1. **创建**存储实例配置和URL
```javascript
async function createNodePassInstance(config) {
const response = await fetch(`${API_URL}/instances`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey // 如果启用了API Key
},
body: JSON.stringify({
url: `server://0.0.0.0:${config.port}/${config.target}?tls=${config.tls}`
})
});
const data = await response.json();
// 根据类型为新实例配置自启动策略
if (data.success) {
const shouldAutoRestart = config.type === 'server' || config.critical === true;
await setAutoStartPolicy(data.data.id, shouldAutoRestart);
}
// 存储在前端持久化存储中
saveInstanceConfig({
id: data.data.id,
originalConfig: config,
url: data.data.url
});
return data;
}
```
2. **状态监控**:监控实例状态变化
NodePass提供两种监控实例状态的方法
A. **使用SSE推荐**:通过持久连接接收实时事件
```javascript
function connectToEventSource() {
const eventSource = new EventSource(`${API_URL}/events`, {
// 如果需要认证,需要使用自定义实现
});
// 或者使用带API Key的自定义实现
// connectToEventSourceWithApiKey(apiKey);
eventSource.addEventListener('instance', (event) => {
const data = JSON.parse(event.data);
// 处理不同类型的事件initial, create, update, delete, log
// ...处理逻辑见前面的"使用SSE实时事件监控"部分
});
// 错误处理和重连逻辑
// ...详见前面的示例
return eventSource;
}
```
B. **传统轮询(备选)**在不支持SSE的环境中使用
```javascript
function startInstanceMonitoring(instanceId, interval = 5000) {
return setInterval(async () => {
try {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
headers: {
'X-API-Key': apiKey // 如果启用了API Key
}
});
const data = await response.json();
if (data.success) {
updateInstanceStatus(instanceId, data.data.status);
updateInstanceMetrics(instanceId, {
connections: data.data.connections,
pool_size: data.data.pool_size,
uptime: data.data.uptime
});
}
} catch (error) {
markInstanceUnreachable(instanceId);
}
}, interval);
}
```
**选择建议:** 优先使用SSE方式它提供更高效的实时监控减轻服务器负担。仅在客户端不支持SSE或需要特定环境兼容性时使用轮询方式。
3. **实例别名管理**:为实例设置易读的名称
```javascript
// 批量设置实例别名
async function setInstanceAliases(instances) {
for (const instance of instances) {
// 根据实例类型和用途生成有意义的别名
const alias = `${instance.type}-${instance.region || 'default'}-${instance.port || 'auto'}`;
await updateInstanceAlias(instance.id, alias);
}
}
// 根据别名查找实例
async function findInstanceByAlias(targetAlias) {
const response = await fetch(`${API_URL}/instances`, {
headers: { 'X-API-Key': apiKey }
});
const data = await response.json();
if (data.success) {
return data.data.find(instance => instance.alias === targetAlias);
}
return null;
}
```
4. **控制操作**:启动、停止、重启实例
```javascript
async function controlInstance(instanceId, action) {
// action可以是: start, stop, restart
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PATCH', // 注意API已更新为使用PATCH方法而非PUT
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey // 如果启用了API Key
},
body: JSON.stringify({ action })
});
const data = await response.json();
return data.success;
}
// 更新实例别名
async function updateInstanceAlias(instanceId, alias) {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey // 如果启用了API Key
},
body: JSON.stringify({ alias })
});
const data = await response.json();
return data.success;
}
// 更新实例URL配置
async function updateInstanceURL(instanceId, newURL) {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey // 如果启用了API Key
},
body: JSON.stringify({ url: newURL })
});
const data = await response.json();
return data.success;
}
```
5. **自启动策略管理**:配置自动启动行为
```javascript
async function setAutoStartPolicy(instanceId, enableAutoStart) {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ restart: enableAutoStart })
});
const data = await response.json();
return data.success;
}
async function controlInstanceWithAutoStart(instanceId, action, enableAutoStart) {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({
action: action,
restart: enableAutoStart
})
});
const data = await response.json();
return data.success;
}
async function updateInstanceComplete(instanceId, alias, action, enableAutoStart) {
const response = await fetch(`${API_URL}/instances/${instanceId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({
alias: alias,
action: action,
restart: enableAutoStart
})
});
const data = await response.json();
return data.success;
}
```
#### 自启动策略完整使用示例
以下是一个全面的示例,展示了如何在实际场景中实现自启动策略管理:
```javascript
// 场景:建立带有自启动策略的负载均衡服务器集群
async function setupServerCluster(serverConfigs) {
const clusterInstances = [];
for (const config of serverConfigs) {
try {
// 创建服务器实例
const instance = await createNodePassInstance({
type: 'server',
port: config.port,
target: config.target,
critical: config.isPrimary, // 主服务器为关键实例
tls: config.enableTLS
});
if (instance.success) {
// 设置有意义的实例别名
const alias = `${config.role}-server-${config.port}`;
await updateInstanceAlias(instance.data.id, alias);
// 根据服务器角色配置自启动策略
const autoStartPolicy = config.isPrimary || config.role === 'essential';
await setAutoStartPolicy(instance.data.id, autoStartPolicy);
// 启动实例
await controlInstance(instance.data.id, 'start');
clusterInstances.push({
id: instance.data.id,
alias: alias,
role: config.role,
autoStartEnabled: autoStartPolicy
});
console.log(`服务器 ${alias} 已创建,自启动策略: ${autoStartPolicy}`);
}
} catch (error) {
console.error(`创建服务器 ${config.role} 失败:`, error);
}
}
return clusterInstances;
}
// 监控集群健康状态并动态调整自启动策略
async function monitorClusterHealth(clusterInstances) {
const healthyInstances = [];
for (const cluster of clusterInstances) {
const instance = await fetch(`${API_URL}/instances/${cluster.id}`, {
headers: { 'X-API-Key': apiKey }
});
const data = await instance.json();
if (data.success && data.data.status === 'running') {
healthyInstances.push(cluster);
} else {
// 如果关键实例宕机,为备份实例启用自启动策略
if (cluster.role === 'primary') {
await enableBackupInstanceAutoStart(clusterInstances);
}
}
}
return healthyInstances;
}
async function enableBackupInstanceAutoStart(clusterInstances) {
const backupInstances = clusterInstances.filter(c => c.role === 'backup');
for (const backup of backupInstances) {
await setAutoStartPolicy(backup.id, true);
console.log(`已为备份实例启用自启动策略: ${backup.id}`);
}
}
```
### 流量统计
主控API提供流量统计数据但需要注意以下重要事项
1. **基本流量指标**NodePass周期性地提供TCP和UDP流量在入站和出站方向上的累计值前端应用需要存储和处理这些值以获得有意义的统计信息。
```javascript
function processTrafficStats(instanceId, currentStats) {
// 存储当前时间戳
const timestamp = Date.now();
// 如果我们有该实例的前一个统计数据,计算差值
if (previousStats[instanceId]) {
const timeDiff = timestamp - previousStats[instanceId].timestamp;
const tcpInDiff = currentStats.tcp_in - previousStats[instanceId].tcp_in;
const tcpOutDiff = currentStats.tcp_out - previousStats[instanceId].tcp_out;
const udpInDiff = currentStats.udp_in - previousStats[instanceId].udp_in;
const udpOutDiff = currentStats.udp_out - previousStats[instanceId].udp_out;
// 存储历史数据用于图表展示
storeTrafficHistory(instanceId, {
timestamp,
tcp_in_rate: tcpInDiff / timeDiff * 1000, // 每秒字节数
tcp_out_rate: tcpOutDiff / timeDiff * 1000,
udp_in_rate: udpInDiff / timeDiff * 1000,
udp_out_rate: udpOutDiff / timeDiff * 1000
});
}
// 更新前一个统计数据,用于下次计算
previousStats[instanceId] = {
timestamp,
tcp_in: currentStats.tcp_in,
tcp_out: currentStats.tcp_out,
udp_in: currentStats.udp_in,
udp_out: currentStats.udp_out
};
}
```
2. **数据持久化**由于API只提供累计值前端必须实现适当的存储和计算逻辑
```javascript
// 前端流量历史存储结构示例
const trafficHistory = {};
function storeTrafficHistory(instanceId, metrics) {
if (!trafficHistory[instanceId]) {
trafficHistory[instanceId] = {
timestamps: [],
tcp_in_rates: [],
tcp_out_rates: [],
udp_in_rates: [],
udp_out_rates: []
};
}
trafficHistory[instanceId].timestamps.push(metrics.timestamp);
trafficHistory[instanceId].tcp_in_rates.push(metrics.tcp_in_rate);
trafficHistory[instanceId].tcp_out_rates.push(metrics.tcp_out_rate);
trafficHistory[instanceId].udp_in_rates.push(metrics.udp_in_rate);
trafficHistory[instanceId].udp_out_rates.push(metrics.udp_out_rate);
// 保持历史数据量可管理
const MAX_HISTORY = 1000;
if (trafficHistory[instanceId].timestamps.length > MAX_HISTORY) {
trafficHistory[instanceId].timestamps.shift();
trafficHistory[instanceId].tcp_in_rates.shift();
trafficHistory[instanceId].tcp_out_rates.shift();
trafficHistory[instanceId].udp_in_rates.shift();
trafficHistory[instanceId].udp_out_rates.shift();
}
}
```
### 实例ID持久化
由于NodePass现在使用gob格式持久化存储实例状态实例ID在主控重启后**不再发生变化**。这意味着:
1. 前端应用可以安全地使用实例ID作为唯一标识符
2. 实例配置、状态和统计数据在重启后自动恢复
3. 不再需要实现实例ID变化的处理逻辑
这极大简化了前端集成消除了以前处理实例重新创建和ID映射的复杂性。
### 自启动策略管理
NodePass现在支持为实例配置自启动策略实现自动化实例管理并提高可靠性。自启动策略功能具备以下特性
1. **自动实例恢复**:启用自启动策略的实例在主控服务重启时会自动启动
2. **选择性自启动**:根据实例的重要性或角色配置哪些实例应该自动启动
3. **持久化策略存储**:自启动策略在主控重启间保存和恢复
4. **细粒度控制**:每个实例都可以有自己的自启动策略设置
#### 自启动策略工作原理
- **策略分配**:每个实例都有一个`restart`布尔字段,决定其自启动行为
- **主控启动**:主控启动时,自动启动所有`restart: true`的实例
- **策略持久化**:自启动策略与其他实例数据一起保存在`nodepass.gob`文件中
- **运行时管理**:自启动策略可以在实例运行时修改
#### 自启动策略最佳实践
1. **为服务器实例启用**:服务器实例通常应启用自启动策略以确保高可用性
2. **选择性客户端自启动**:仅为关键客户端连接启用自启动策略
3. **测试场景**:为临时或测试实例禁用自启动策略
4. **负载均衡**:使用自启动策略维持最小实例数量以分配负载
```javascript
// 示例:根据实例角色配置自启动策略
async function configureAutoStartPolicies(instances) {
for (const instance of instances) {
// 为服务器和关键客户端启用自启动
const shouldAutoStart = instance.type === 'server' ||
instance.tags?.includes('critical');
await setAutoStartPolicy(instance.id, shouldAutoStart);
}
}
```
## 实例数据结构
API响应中的实例对象包含以下字段
```json
{
"id": "a1b2c3d4", // 实例唯一标识符
"alias": "web-server-01", // 实例别名(可选,用于显示友好名称)
"type": "server", // 实例类型server 或 client
"status": "running", // 实例状态running、stopped 或 error
"url": "server://...", // 实例配置URL
"restart": true, // 自启动策略
"mode": 0, // 运行模式
"tcprx": 1024, // TCP接收字节数
"tcptx": 2048, // TCP发送字节数
"udprx": 512, // UDP接收字节数
"udptx": 256 // UDP发送字节数
}
```
**注意:**
- `alias` 字段为可选,如果未设置则为空字符串
- `mode` 字段表示实例当前的运行模式
- `restart` 字段控制实例的自启动行为
## 系统信息端点
`/info` 端点提供了关于NodePass主控服务的系统信息。这个端点对于监控、故障排除和系统状态验证非常有用。
### 请求
```
GET /info
```
需要 API Key 认证:是
### 响应
响应包含以下系统信息字段:
```json
{
"os": "linux", // 操作系统类型
"arch": "amd64", // 系统架构
"cpu": 45, // CPU使用率百分比仅Linux系统
"mem_total": 8589934592, // 内存容量字节仅Linux系统
"mem_free": 2684354560, // 内存可用字节仅Linux系统
"swap_total": 3555328000, // 交换区总量字节仅Linux系统
"swap_free": 3555328000, // 交换区可用字节仅Linux系统
"netrx": 1048576000, // 网络接收字节数累计值仅Linux
"nettx": 2097152000, // 网络发送字节数累计值仅Linux
"diskr": 4194304000, // 磁盘读取字节数累计值仅Linux
"diskw": 8388608000, // 磁盘写入字节数累计值仅Linux
"sysup": 86400, // 系统运行时间仅Linux
"ver": "1.2.0", // NodePass版本
"name": "example.com", // 隧道主机名
"uptime": 11525, // API运行时间
"log": "info", // 日志级别
"tls": "1", // TLS启用状态
"crt": "/path/to/cert", // 证书路径
"key": "/path/to/key" // 密钥路径
}
```
### 使用示例
```javascript
// 获取系统信息
async function getSystemInfo() {
const response = await fetch(`${API_URL}/info`, {
method: 'GET',
headers: {
'X-API-Key': apiKey
}
});
return await response.json();
}
// 显示服务运行时间和系统资源使用情况
function displaySystemStatus() {
getSystemInfo().then(info => {
console.log(`服务已运行: ${info.uptime} 秒`);
// 格式化运行时间为更友好的显示
const hours = Math.floor(info.uptime / 3600);
const minutes = Math.floor((info.uptime % 3600) / 60);
const seconds = info.uptime % 60;
console.log(`服务已运行: ${hours}小时${minutes}分${seconds}秒`);
// 显示系统资源使用情况仅Linux系统
if (info.os === 'linux') {
if (info.cpu !== -1) {
console.log(`CPU使用率: ${info.cpu}%`);
}
if (info.mem_total > 0) {
const memUsagePercent = ((info.mem_total - info.mem_free) / info.mem_total * 100).toFixed(1);
console.log(`内存使用率: ${memUsagePercent}% (${(info.mem_free / 1024 / 1024 / 1024).toFixed(1)}GB 可用,共 ${(info.mem_total / 1024 / 1024 / 1024).toFixed(1)}GB)`);
}
if (info.swap_total > 0) {
const swapUsagePercent = ((info.swap_total - info.swap_free) / info.swap_total * 100).toFixed(1);
console.log(`交换区使用率: ${swapUsagePercent}% (${(info.swap_free / 1024 / 1024 / 1024).toFixed(1)}GB 可用,共 ${(info.swap_total / 1024 / 1024 / 1024).toFixed(1)}GB)`);
}
} else {
console.log('CPU、内存、交换区、网络I/O、磁盘I/O和系统运行时间监控功能仅在Linux系统上可用');
}
// 显示网络I/O统计累计值
if (info.os === 'linux') {
console.log(`网络接收: ${(info.netrx / 1024 / 1024).toFixed(2)} MB累计`);
console.log(`网络发送: ${(info.nettx / 1024 / 1024).toFixed(2)} MB累计`);
console.log(`磁盘读取: ${(info.diskr / 1024 / 1024).toFixed(2)} MB累计`);
console.log(`磁盘写入: ${(info.diskw / 1024 / 1024).toFixed(2)} MB累计`);
console.log(`系统运行时间: ${Math.floor(info.sysup / 3600)}小时`);
}
});
}
```
### 监控最佳实践
- **定期检查**:定期轮询此端点以确保服务正常运行
- **版本验证**:在部署更新后检查版本号
- **运行时间监控**:监控运行时间以检测意外重启
- **日志级别验证**:确认当前日志级别符合预期
- **资源监控**在Linux系统上监控CPU、内存、交换区、网络I/O、磁盘I/O使用情况以确保最佳性能
- CPU使用率通过解析`/proc/stat`计算(非空闲时间百分比)
- 内存信息通过解析`/proc/meminfo`获取(总量和可用量,单位为字节)
- 交换区信息通过解析`/proc/meminfo`获取(总量和可用量,单位为字节)
- 网络I/O通过解析`/proc/net/dev`计算(累计字节数,排除虚拟接口)
- 磁盘I/O通过解析`/proc/diskstats`计算(累计字节数,仅统计主设备)
- 系统运行时间通过解析`/proc/uptime`获取
- 值为-1或0表示系统信息不可用非Linux系统
- 网络和磁盘I/O字段提供的是累计值前端应用需要存储历史数据并计算差值来得到实时速率字节/秒)
## API端点文档
有关详细的API文档包括请求和响应示例请使用`/docs`端点提供的内置Swagger UI文档。这个交互式文档提供了以下全面信息
- 可用的端点
- 必需的参数
- 响应格式
- 请求和响应示例
- 架构定义
### 访问Swagger UI
要访问Swagger UI文档
```
http(s)://<api_addr>[<prefix>]/docs
```
例如:
```
http://localhost:9090/api/docs
```
Swagger UI提供了一种方便的方式直接在浏览器中探索和测试API。您可以针对运行中的NodePass主控实例执行API调用并查看实际响应。
## 完整的API参考
### 实例管理端点详细说明
#### GET /instances
- **描述**:获取所有实例列表
- **认证**需要API Key
- **响应**:实例数组
- **示例**
```javascript
const instances = await fetch(`${API_URL}/instances`, {
headers: { 'X-API-Key': apiKey }
});
```
#### POST /instances
- **描述**:创建新实例
- **认证**需要API Key
- **请求体**`{ "url": "client://或server://格式的URL" }`
- **响应**:新创建的实例对象
- **示例**
```javascript
const newInstance = await fetch(`${API_URL}/instances`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ url: 'server://0.0.0.0:8080/localhost:3000' })
});
```
#### GET /instances/{id}
- **描述**:获取特定实例详情
- **认证**需要API Key
- **响应**:实例对象
- **示例**
```javascript
const instance = await fetch(`${API_URL}/instances/abc123`, {
headers: { 'X-API-Key': apiKey }
});
```
#### PATCH /instances/{id}
- **描述**:更新实例状态、别名或执行控制操作
- **认证**需要API Key
- **请求体**`{ "alias": "新别名", "action": "start|stop|restart|reset", "restart": true|false }`
- **特点**:不中断正在运行的实例,仅更新指定字段。`action: "reset"` 可将该实例的流量统计tcprx、tcptx、udprx、udptx清零。
- **示例**
```javascript
// 更新别名和自启动策略
await fetch(`${API_URL}/instances/abc123`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({
alias: 'Web服务器',
restart: true
})
});
// 控制实例操作
await fetch(`${API_URL}/instances/abc123`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ action: 'restart' })
});
// 清零流量统计
await fetch(`${API_URL}/instances/abc123`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ action: 'reset' })
});
```
#### PUT /instances/{id}
- **描述**完全更新实例URL配置
- **认证**需要API Key
- **请求体**`{ "url": "新的client://或server://格式的URL" }`
- **特点**:会重启实例。
- **限制**API Key实例ID为`********`)不支持此操作
- **示例**
```javascript
// 更新实例URL
await fetch(`${API_URL}/instances/abc123`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({
url: 'server://0.0.0.0:9090/localhost:8080?tls=1'
})
});
```
#### DELETE /instances/{id}
- **描述**:删除实例
- **认证**需要API Key
- **响应**204 No Content
- **限制**API Key实例ID为`********`)不可删除
- **示例**
```javascript
await fetch(`${API_URL}/instances/abc123`, {
method: 'DELETE',
headers: { 'X-API-Key': apiKey }
});
```
### 其他端点
#### GET /events
- **描述**建立SSE连接以接收实时事件
- **认证**需要API Key
- **响应**Server-Sent Events流
- **事件类型**`initial`, `create`, `update`, `delete`, `shutdown`, `log`
#### GET /info
- **描述**:获取主控服务信息
- **认证**需要API Key
- **响应**包含系统信息、版本、运行时间、CPU和RAM使用率等
#### GET /tcping
- **描述**TCP连接测试检测目标地址的连通性和延迟
- **认证**需要API Key
- **参数**
- `target`(必需):目标地址,格式为 `host:port`
- **响应**
```json
{
"target": "example.com:80",
"connected": true,
"latency": 45,
"error": null
}
```
- **示例**`GET /api/tcping?target=fast.com:443`
#### GET /openapi.json
- **描述**获取OpenAPI 3.1.1规范
- **认证**:无需认证
- **响应**JSON格式的API规范
#### GET /docs
- **描述**Swagger UI文档界面
- **认证**:无需认证
- **响应**HTML格式的交互式文档
### 实例URL格式规范
实例URL必须遵循以下格式
#### 服务器模式 (Server Mode)
```
server://<bind_address>:<bind_port>/<target_host>:<target_port>?<parameters>
```
示例:
- `server://0.0.0.0:8080/localhost:3000` - 在8080端口监听转发到本地3000端口
- `server://0.0.0.0:9090/localhost:8080?tls=1&mode=1` - 启用TLS的服务器强制反向模式
#### 客户端模式 (Client Mode)
```
client://<server_host>:<server_port>/<local_host>:<local_port>?<parameters>
```
示例:
- `client://example.com:8080/localhost:3000` - 连接到远程服务器本地监听3000端口
- `client://remote.example.com:443/localhost:22?mode=2&min=32` - 通过远程服务器,强制双端模式
#### 支持的参数
| 参数 | 描述 | 值 | 默认值 | 适用范围 |
|------|------|----|----|---------|
| `log` | 日志级别 | `none`, `debug`, `info`, `warn`, `error`, `event` | `info` | 两者 |
| `tls` | TLS加密级别 | `0`(无), `1`(自签名), `2`(证书) | `0` | 仅服务器 |
| `crt` | 证书路径 | 文件路径 | 无 | 仅服务器 |
| `key` | 私钥路径 | 文件路径 | 无 | 仅服务器 |
| `mode` | 运行模式控制 | `0`(自动), `1`(强制模式1), `2`(强制模式2) | `0` | 两者 |
| `min` | 最小连接池容量 | 整数 > 0 | `64` | 仅客户端双端握手模式 |
| `max` | 最大连接池容量 | 整数 > 0 | `1024` | 双端握手模式 |
| `read` | 读取超时时间 | 时间长度 (如 `10m`, `30s`, `1h`) | `10m` | 两者 |
| `rate` | 带宽速率限制 | 整数 (Mbps), 0=无限制 | `0` | 两者 |
| `proxy` | PROXY协议支持 | `0`(禁用), `1`(启用) | `0` | 两者 |