# NexusGate 面板 Go 移植 — 行为对齐说明(PARITY) Go 版(本目录)是 Node 版(../server.js + ../lib/)的 1:1 移植:同一 `nexusgate.json`、同一 HTTP API、同一前端(public/ 零改动,embed 进二进制)。 版本号保持 `0.6.8`(agent 的 AnyTLS 版本门禁按数字解析面板下发的版本串, 且 overview/healthz 的 version 字段与 Node 一致)。 ## 已验证等价(2026-10-20,沙箱内) - **Go 单元测试 33/33**:含 scrypt 测试向量 6 组(由 Node 实现生成, `testdata/scrypt_vectors.json`,逐字节一致)、Reality 密钥向量 4 组 (固定私钥→公钥推导与 Node JWK 导出一致)、资源构建黄金深比较、 订阅 8 种格式黄金**逐字节**一致、store 事务/原子写/未知字段透传。 - **Node 测试 52/52**:未改动任何 Node 文件,原样全绿。 - **差分 E2E 正式模式 50/50**(`difftest/run.mjs`):同一种子 DB(由 Node 面板自身业务流生成)分别起 Node/Go 面板,跑登录/CSRF、建服务器+注册 令牌、agent enroll→带 resources 心跳→对账重排→poll→complete、建节点+ 客户+分配→订阅全格式逐字比对、用量上报、节点删除/服务器遗忘、备份 比对、错误用例;随后**交换 DB 文件**互启对方实现,列表/订阅/写入均 正常,keyStore/jobs/用量不丢。 - **三态字段已精确建模**(差分首轮抓到并修复):`nodes.autoRemoving` (缺失 vs 显式 false)、`servers.engine`(缺失 vs 显式 null)、 `customers.suspendReason`(缺失 vs 显式 null)在 Go 版用 指针/presence 标志区分,加载、响应、写回均与 Node 一致。 - 未知字段(其他版本写入的键)在记录级与顶层均透传保留,Node 写的 DB 由 Go 加载再写回不丢字段(store 测试 + 互通步骤双重覆盖)。 ## 已知微偏差(均为边缘路径,不影响线上业务流) 1. **Cookie 解析**:值含畸形 `%` 转义时 JS `decodeURIComponent` 抛错 (请求 500);Go 跳过该对。Go 的 PathUnescape 也不拒绝非法 UTF-8 字节序列(JS 会抛错)。 2. **VerifySecret 的 hex 解码**:JS `Buffer.from(hex,'hex')` 对非法 hex 是截断容忍,Go 严格解码失败即 false;最终判定结果一致。 3. **字符串截断口径**:CleanText、错误截断(1800/240/80)、access 的 128/200 上限,Go 按 rune、JS 按 UTF-16 码元;仅星平面字符(emoji 等)恰在边界时可能差 1 字符。新密码 10 位长度校验同此口径。 4. **settings 缺失判定**:Go 用值结构体,以「五字段全零且无 Extra」 近似 JS 的 `!data.settings`;真实写路径不会产生全零 settings, 不可达。 5. **订阅信息页日期**:Go 按存储值(UTC)以 `2006/01/02 15:04:05` 格式化;JS `toLocaleString('zh-CN')` 按服务器本地时区渲染且随 ICU 版本可能有差异(旧 ICU 带上午/下午标记)。百分比 `%.1f` 与 JS `toFixed(1)` 在 .x5 边界可能差 0.1。 6. **NG_DATA_FILE 默认值**:Go 取可执行文件同目录 `data/nexusgate.json`, JS 取源码目录 `__dirname/data`;正式部署都显式设置该变量,无影响。 NG_PORT 不可解析时 Go 回退 8787,JS 为 NaN 监听失败。 7. **ReadJSON 边缘**:body 为 `null` 时 Go 视为空对象,JS 返回 null 后在个别 handler 会 500;非对象 JSON 体 Go 返回 400,JS 各 handler 自行退化。路由参数解码失败时 Go 保留原始段,JS 抛错 500。 8. **JSString 近似**:对象/数组入参 Go 返回 "",JS 为 `"[object Object]"`/逗号拼接;现有 handler 不可达。 OptionalISO 只接受 ParseISO 覆盖的格式,JS `Date` 还接受 `2026/10/20` 等写法(Go 返回 400)。 9. **DNS 失败文案**:resolveBindAddress 报错括号内 Go 用解析器简述 (如 `no such host`),JS 用 getaddrinfo 的 code(如 ENOTFOUND); 仅 DNS 解析失败路径的文案细节不同。 10. **keyMaterial 回填遍历顺序**:多 keyId 时 Go map 迭代序与 JS 对象序不同,audit 先后可能不同;各 key 相互独立,结果等价。 11. **JSON 键序**:Go 响应/落盘的键序为结构体字段序(合并未知字段 时为字母序),JS 为插入序;JSON 语义等价,双方互读无碍(互通 步骤已验证)。 12. **HTTP 超时**:Go ReadHeaderTimeout 15s + ReadTimeout 30s 近似 Node 的 headersTimeout/requestTimeout 语义。 13. **TLS 域名校验**:RE2 不支持 lookahead,总长度 253 改在代码中 校验,接受/拒绝结果一致。 14. **畸形请求建记录**:节点创建缺 name 时 Go 存 "",JS 该键缺失; 服务器 labels 缺省 Go 为 `[]`,JS 为 undefined;仅手工畸形请求 可见,前端正常请求不触发。 ## 构建与产物 - `build.sh`:从 ../public 刷新 embed_public 后 CGO_ENABLED=0 构建。 - 交叉编译(发布):`CGO_ENABLED=0 GOOS=linux GOARCH=amd64|arm64 go build -trimpath -ldflags="-s -w"`, 产物 `nexusgate-panel-linux-{amd64,arm64}`,纯静态、无外部依赖。 - 运行时可用 `NG_PUBLIC_DIR` 指定外部静态目录覆盖 embed(调试用)。