服务器管理 dev 5.2.x 沿用 main 4.1.x 已交付
版本边界(以 qxj_harmony_next_pad_nsp_browser 仓库为准)
- 服务器管理能力在 main 4.1.54 中已完整交付:多套预置、运行时切换、扫码绑定、JSON 导入导出与持久化,是甲方验收内容。
- dev 5.2.89 的 common 模型与 device 管理页与 main 完全一致(两分支该模块 diff 仅版本号字段),多标签并未改变服务器配置体系。
- 旧文档中「main 仅一套固定服务器、多服务器为 dev 独有」的说法与代码不符,已废弃。
1. 设计目标
项目存在多套部署环境(甲方正式环境、外网联调环境、开发本地环境等),每套环境的鉴权服务与业务服务地址各不相同。服务器管理模块要解决四个问题:
- 多环境并存:同时保存多套服务器配置,用户可在不重装、不改包的情况下切换;
- 可信绑定:每套服务器通过扫码绑定其
serverId与 SM2 公钥,作为后续设备注册与 SM2 握手的信任根; - 配置可迁移:支持 JSON 导入导出,便于批量部署与现场运维;
- 安全联动:切换 / 修改服务器后,JSBridge 注入白名单立即跟随变化,默认拒绝(fail-closed)。
4. 交付版(main 4.1.x · 甲方交付)
4.1 服务器配置模型
每套服务器由 common 模块的 ServerConfig 类描述,共 7 个字段:
| 字段 | 含义 |
|---|---|
name | 服务器名称(列表展示用) |
backendUrl | 鉴权后端地址(登录、令牌、握手) |
frontendUrl | 鉴权前端地址 |
businessBackendUrl | 业务后端地址(/api/v3 业务接口) |
businessFrontendUrl | 业务前端地址(Web 页面,浏览器默认加载) |
serverId | 服务器设备 ID,扫码绑定后填充,默认空 |
serverPubKey | 服务器 SM2 公钥(128 hex),扫码绑定后填充,默认空 |
其中前 5 项为连接信息,后 2 项为绑定凭证:只有扫码绑定后,该服务器才处于「已绑定」可鉴权状态。
4.2 出厂预置与当前选中
- 出厂预置列表
LISTS_SAVED当前启用 2 套:JD_Server_HTTPS(外网测试服务器 HTTPS,DEFAULT_SERVER,默认选中)与Ali_Server_HTTPS;代码中还保留了气象局正式、本地台式机、ThinkBook 热点等多套候选配置,按交付需要注释切换。 - 每套环境固定使用四个标准端口语义:鉴权后端
4607、鉴权前端3006、业务后端8080、业务前端5173。 - 「当前服务器」以索引表示(
CURRENT_SERVER_INDEX),而非拷贝一份配置对象;切换只是改索引,天然避免多处配置副本不一致。
4.3 多套配置的增删与切换
服务器管理页(ServerConfigView + ServerConfigVM,MVVM)提供完整的列表操作:
- 新增:填写名称与四个 URL(名称、鉴权后端必填)后置顶插入并自动选中;通过创建新数组写回 AppStorage 以触发
@StorageLink刷新。 - 删除:删除后自动修正当前索引——删的是当前项则回到第一项,删的是当前项之前的项则索引前移,保证索引始终有效。
- 切换:索引无效或未变化时直接返回;真正切换时做两件事:
- 异步清理旧服务器会话:调用
JsBridgeHandle.performFullLogout(oldServer)注销旧服务器令牌与会话(不阻塞切换,异常只记录); - 写入新索引并提示「已切换,原服务器会话已清理」,防止旧环境令牌被带到新环境造成串号。
- 异步清理旧服务器会话:调用
4.4 扫码绑定公钥
绑定流程由 handleBindScanInfo 实现,是设备信任链的入口:
- 调起系统扫码(ScanKit,经
@pura/picker_utils封装),扫描设备注册二维码; - 二维码内容格式为
serverId#timestamp#serverPubKey,由DeviceRegisterUtil.parseServerQr解析,格式不合法即提示无效二维码; - 把解析出的
serverId与serverPubKey写入目标配置并触发列表刷新; - 支持解绑(
serverId/serverPubKey置空),恢复未绑定状态后可重新扫码。
绑定状态的判断由模块级函数 isServerBound(c) 承担(真值判断:serverId 与 serverPubKey 均非空),而非类方法——原因见下节。
4.5 持久化与反序列化坑
- 持久化方式:通过
PersistentStorage.persistProp注册两个键——server_config_list_v2(列表,默认值为LISTS_SAVED)与current_server_index_v2(索引,默认 0)。使用v2后缀与旧字段结构隔离。 - 初始化时机:PersistentStorage 依赖 UI 实例,必须在入口
loadContent完成后调用initServerConfigPersistentStorage()(模块内以标记保证幂等),过早调用会静默持久化失败。 - 反序列化丢方法:从 PersistentStorage 读回的对象只是普通数据对象,类原型上的方法全部丢失,因此不能调用
item.isBound()之类方法,必须使用模块级的isServerBound()。 - 旧数据字段缺失:旧版本持久化数据可能没有
serverId/serverPubKey(值为undefined)。若用!== ''判定会把undefined误判为「已绑定」(undefined !== ''为 true),故必须用真值判断。这两个坑都在代码注释中明确记录,是维护时的高频陷阱。
4.6 JSON 导入导出
- 导出:
exportServerConfigJson将当前全部配置序列化为 JSON 文件,经文件保存器落盘;空列表、用户取消、失败分别给出对应提示。 - 导入支持两种来源:
- 文件导入:经系统文件选择器选取 JSON,
parseServerConfigJson解析; - 扫码导入:直接扫描内容为配置 JSON 的二维码,适合现场无文件通道的场景。
- 文件导入:经系统文件选择器选取 JSON,
- 合并策略:导入列表与当前列表按名称合并,同名配置跳过而非覆盖,避免一次误扫码冲掉已有环境。
4.7 JSBridge origin 白名单联动(fail-closed)
服务器配置同时是 JSBridge 安全边界的数据源(安全修复 F-15):
- 风险背景:
javaScriptProxy默认会把桥对象注入 Web 加载的所有页面,用户浏览的任意第三方网页都能调用登录、取令牌、加解密等方法,构成令牌窃取、加密预言机与静默钓鱼登录三重风险。 - 白名单来源:取当前选中服务器的四个 URL,解析为
scheme / host / port / path条目(scheme、host 精确匹配,port 精确、空串不检查,path 前缀匹配),通过 API 12+javaScriptProxy的permission参数声明允许注入的源。 - 最小授权:只有当前服务器的地址进入白名单,未选中服务器的地址不注入;当前服务器未配置或索引越界时白名单为空 → 全部源禁止注入(fail-closed)。
- 跟随刷新:白名单在 Web 创建时固定。
BrowserView通过@Watch监听服务器选择与配置变化(refreshServerDisplay),变化时以jsbEpoch递增触发 Web 重建,使新白名单立即生效;应用侧另有isOriginAllowed/checkOriginAllowed做运行时 origin 校验,与注入白名单共用同一数据源、形成双层防护。
5. 实验版(dev 5.2.x)
服务器管理在 5.x 中没有新增能力,可视为 4.x 设计的稳定复用:
ServerConfig模型、持久化键、扫码绑定与 JSON 导入导出逻辑在 dev 与 main 上一致;出厂预置与默认项相同。- dev 的差异主要体现在多标签消费侧:浏览器存在多个离线 Web 实例时,桥白名单仍以「当前选中服务器」为唯一数据源,切换服务器后的白名单重算与 Web 重建机制需要与离线标签的挂载机制协同;这部分跟随多标签方案一起仍在验证中。
因此对甲方交付而言,服务器管理以 main 4.1.x 为准即可;dev 不提供额外承诺。
6. 设计要点回顾
- 索引而非副本:当前环境只存索引,配置只有一份事实来源,切换无同步成本。
- 切换即清场:切服务器时异步登出旧环境,杜绝跨环境令牌串用。
- 信任根可核验:扫码绑定
serverId + SM2 公钥,为公钥体系提供带外验证通道,避免手工录入公钥被篡改。 - 默认拒绝的安全姿态:白名单完全由当前服务器配置推导,异常时空名单全拒,把配置错误的安全后果降到最低。
- 正视平台持久化的语义:反序列化丢原型、旧字段可能为
undefined,用模块级函数与真值判断规避,都是实际踩坑后沉淀的经验。