Go SDK
XLADA 没有官方的 Go SDK。XLADA 的 API 与 Remnawave 的 API 完全一致,
因此客户端可以用标准库 net/http 搭建,不需要任何外部
依赖 —— 这样你就不依赖他人的发布周期。
兼容性
社区为 Remnawave 维护着由同一份 OpenAPI 规范生成的 Go SDK。 XLADA 对相同的路径作出响应,因此它在这里同样适用, 但我们没有用 XLADA 对它做过官方测试。下面的示例不依赖任何模块。
安装
需要 Go 1.18+(用到了 any)以及项目模块:
mkdir xlada-bot && cd xlada-bot
go mod init example.com/xlada-bot
不需要外部包 —— 只需要 net/http、encoding/json 和 context。
客户端
令牌可以是 POST /api/auth/login 返回的 JWT,也可以是
POST /api/tokens 返回的长期 API 令牌。两者都通过
Authorization: Bearer 请求头传递。直接访问面板时,请加上
X-Forwarded-For 和 X-Forwarded-Proto: https 请求头,
否则面板的 middleware 会断开连接。
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Client struct {
baseURL string
token string
http *http.Client
}
func NewClient(baseURL, token string) *Client {
return &Client{
baseURL: baseURL,
token: token,
http: &http.Client{Timeout: 30 * time.Second},
}
}
func (c *Client) do(ctx context.Context, method, path string, body, out any) error {
var payload []byte
if body != nil {
var err error
if payload, err = json.Marshal(body); err != nil {
return err
}
}
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, bytes.NewReader(payload))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.token)
req.Header.Set("X-Forwarded-For", "127.0.0.1")
req.Header.Set("X-Forwarded-Proto", "https")
res, err := c.http.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("xlada: %s %s: %s", method, path, res.Status)
}
if out != nil {
return json.NewDecoder(res.Body).Decode(out)
}
return nil
}
用户列表
分页输出由查询参数 start(偏移量)和 size
(每页大小,1–1000)指定。
type user struct {
ID int `json:"id"`
Username string `json:"username"`
Status string `json:"status"`
ShortUUID string `json:"shortUuid"`
ExpireAt string `json:"expireAt"`
}
type usersResponse struct {
Response struct {
Users []user `json:"users"`
Total int `json:"total"`
} `json:"response"`
}
func listUsers(ctx context.Context, c *Client) error {
var out usersResponse
if err := c.do(ctx, http.MethodGet, "/api/users?start=0&size=25", nil, &out); err != nil {
return err
}
for _, u := range out.Response.Users {
fmt.Printf("%s\t%s\t%s\n", u.Username, u.Status, u.ExpireAt)
}
fmt.Printf("总计: %d\n", out.Response.Total)
return nil
}
创建用户
POST /api/users 接受 username(3–36 个字符,仅限 a-z、A-Z、
0-9、_、-)以及必填的、ISO 8601 格式的 expireAt。
type createUserRequest struct {
Username string `json:"username"`
Status string `json:"status,omitempty"`
ExpireAt string `json:"expireAt"`
TrafficLimitBytes int64 `json:"trafficLimitBytes,omitempty"`
TrafficLimitStrategy string `json:"trafficLimitStrategy,omitempty"`
}
func createUser(ctx context.Context, c *Client) error {
var out struct {
Response struct {
ID int `json:"id"`
ShortUUID string `json:"shortUuid"`
} `json:"response"`
}
err := c.do(ctx, http.MethodPost, "/api/users", createUserRequest{
Username: "john_doe",
Status: "ACTIVE",
ExpireAt: "2026-01-17T15:38:45.065Z",
TrafficLimitStrategy: "NO_RESET",
}, &out)
if err != nil {
return err
}
fmt.Printf("已创建 id=%d, shortUuid=%s\n", out.Response.ID, out.Response.ShortUUID)
return nil
}
获取节点
具体节点通过 uuid 查询,节点列表通过 GET /api/nodes 查询。
func getNode(ctx context.Context, c *Client, uuid string) error {
var out struct {
Response struct {
Name string `json:"name"`
Address string `json:"address"`
Port *int `json:"port"`
IsConnected bool `json:"isConnected"`
} `json:"response"`
}
if err := c.do(ctx, http.MethodGet, "/api/nodes/"+uuid, nil, &out); err != nil {
return err
}
fmt.Printf("%s (%s) connected=%v\n", out.Response.Name, out.Response.Address, out.Response.IsConnected)
return nil
}
提示
所有响应结构都在 API Specification 页面的规范中有说明。
json 标签直接取自那里 —— 面板的字段
使用 camelCase 命名。
接下来
- TypeScript SDK —— 基于
fetch和 axios 的客户端。 - Python SDK —— 基于
requests的客户端。 - API Specification —— 完整的 OpenAPI 规范。
- Webhooks —— 无需轮询 API 的面板事件。