171 lines
14 KiB
Markdown
171 lines
14 KiB
Markdown
# 公网服务端「添加 / 编辑」弹窗表单合理性分析
|
||||
|
|
|
|||
|
|
> 分析对象:`F:\Fonu-main\havline\web\src\views\AgentView.vue` 中的服务端弹窗(`showServerModal`)
|
|||
|
|
> 重点:**「远程管理」标签**(`serverFormTab === 'remote'`,模板 464–540 行)
|
|||
|
|
> 性质:静态代码审查(未运行、未修改),用于后续评审与改进。
|
|||
|
|
> 结论先行:整体结构清晰、密文回显与插件提示较完善,但**「远程管理」标签的帮助栏与标签页不匹配、表单缺少任何校验、`enabled` 字段无 UI 入口**,属于需要优先修复的合理性问题。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、分析对象与背景
|
|||
|
|
|
|||
|
|
- 该弹窗同时用于「添加服务端」和「编辑服务端」(`openServerModal`,1407 行),标题随 `editingServer` 切换。
|
|||
|
|
- 表单分为三个标签页(tabbar,404–406 行):
|
|||
|
|
1. `basic` 基础配置(410 行起):名称/地址/端口/认证(含 OIDC)/描述。
|
|||
|
|
2. `advanced` 高级配置(542 行起):frpc 日志级别、传输协议、TLS、连接调优。
|
|||
|
|
3. `remote` 远程管理(464 行起):frps 服务端参数、管理接口、公网 Agent 接入。
|
|||
|
|
- 三块面板通过 `v-show` 切换,共用一个 `<n-form>`(409 行)和底部单个「保存」按钮(`saveServer`,1603 行)。
|
|||
|
|
- 本次重点分析的「远程管理」标签包含 4 个区块:
|
|||
|
|
- `frps vhost 与域名反代`(466–491)
|
|||
|
|
- `TCP/UDP 端口分配`(493–500)
|
|||
|
|
- `frps 管理接口`(502–521)
|
|||
|
|
- `公网 Agent 管理`(523–540)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、表单整体结构观察
|
|||
|
|
|
|||
|
|
| 观察点 | 现状 | 合理性判断 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| 标签顺序 | tabbar 顺序为 基础 / 高级 / 远程;DOM 面板顺序为 basic / remote / advanced(`v-show` 不影响显示,但维护易错位) | 基本可用,但 DOM 与 tab 顺序不一致,改动时易踩坑 |
|
|||
|
|
| 表单校验 | `<n-form label-placement="top" class="proxy-modal__pane" @submit.prevent="saveServer">`,**无 `:model`、无 `:rules`** | ⚠️ 偏弱:`required` 仅显示星号,不产生校验 |
|
|||
|
|
| 提交按钮 | 三页共用底部「保存」,只写数据库 | ⚠️ 与"远端需下发/重启才生效"的语义割裂 |
|
|||
|
|
| 密文字段 | Token / OIDC Secret / Dashboard 密码 / SSH 密码密钥 / Agent Token 统一用 `ConfiguredSecretField` | ✅ 较好,编辑留空保持不变 |
|
|||
|
|
| 危险操作 | 「清除管理密码」「清除证书/密钥/CA」均有独立按钮 | ✅ 较好 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、「远程管理」标签逐区块分析
|
|||
|
|
|
|||
|
|
### 3.1 frps vhost 与域名反代(466–491 行)
|
|||
|
|
|
|||
|
|
字段:HTTP 回源端口 `vhost_http_port`、HTTPS 回源端口 `vhost_https_port`、子域名根 `sub_domain_host`、tcpmux 监听端口 `tcpmux_http_connect_port`、自定义 404 页面 `custom_404_page`、强制 TLS `tls_force`、frps 写文件日志 `frps_log_to_file`、日志保留天数 `frps_log_max_days`。
|
|||
|
|
|
|||
|
|
合理之处:
|
|||
|
|
- 对 80/443 冲突有专门告警(469 行),并解释"应由 Nginx 占用"。
|
|||
|
|
- 提示了"修改后需下发并重启、重新部署规则"的必要性。
|
|||
|
|
|
|||
|
|
问题:
|
|||
|
|
1. **本质是 frps 服务端配置,却归入"远程管理"**:`vhostHTTPPort/vhostHTTPSPort/subDomainHost/tcpmux` 是 frps.toml 的服务端参数,与"是否远程管理"无关;`tls_force`、`frps_log_*` 同样是 frps 服务端行为。标签命名与内容职责不匹配。
|
|||
|
|
2. **端口冲突无校验**:只对 `==80/443` 告警,未校验 `vhost_http_port` 与 `vhost_https_port`、`server_port`(默认 7000)、`dashboard_port`、`tcpmux_http_connect_port` 之间的重复。
|
|||
|
|
3. **`tls_force` 与高级标签的 `tls_enabled` 无联动**:类型注释已写明"frpc 必须开 transport.tls.enable"(types.ts 405 行),但两字段分属不同标签、互不校验,配置成 `tls_force=true` + `tls_enabled=false` 时连接会失败。
|
|||
|
|
4. **默认值呈现不一致**:placeholder 写"默认 8080/8443",但 `defaultServerOptions()`(1291 行)**不包含** `vhost_http_port/vhost_https_port/sub_domain_host/tcpmux_http_connect_port/custom_404_page/tls_force/frps_log_to_file/frps_log_max_days/allow_ports/max_ports_per_client`,新增服务端时这些字段为 `undefined`。
|
|||
|
|
5. **`custom_404_page` 无格式/存在性校验**(VPS 本地路径只能靠后端报错)。
|
|||
|
|
6. **`sub_domain_host` 的依赖关系未提示校验**(规则用 subdomain 时才生效,属跨模块依赖)。
|
|||
|
|
|
|||
|
|
### 3.2 TCP/UDP 端口分配(493–500 行)
|
|||
|
|
|
|||
|
|
字段:`allow_ports`(端口白名单)、`max_ports_per_client`。
|
|||
|
|
|
|||
|
|
- 说明文字较准确(区分 vhost 回源端口不在此限制、需云安全组与主机防火墙放行)。
|
|||
|
|
- 问题:`allow_ports` 为纯文本,格式(`6000,6005-6010`)无前端校验,错误只会在后端/下发阶段暴露;`max_ports_per_client` 允许 0(不限)与 `n-input-number` 默认空值语义需要靠文案理解。
|
|||
|
|
|
|||
|
|
### 3.3 frps 管理接口(502–521 行)
|
|||
|
|
|
|||
|
|
字段:`dashboard_addr`、`dashboard_port`、`dashboard_user`、`dashboard_password`(密文)+「清除管理密码」。
|
|||
|
|
|
|||
|
|
- 说明清楚地区分了"仅用于 Havline 拉取流量,与连接认证无关"。
|
|||
|
|
- 问题:
|
|||
|
|
1. **成对字段无关联校验**:只填 `dashboard_port` 不填 `dashboard_addr`(或反之)时无提示,仅静默不采集。
|
|||
|
|
2. 该区块与「远程管理」标签主题(Agent/远程)关联度弱,它其实是 frps 的可观测性配置。
|
|||
|
|
|
|||
|
|
### 3.4 公网 Agent 管理(523–540 行)
|
|||
|
|
|
|||
|
|
字段:`agent_url`、`agent_token`、`ssh_host`、`ssh_port`、`ssh_user`、`ssh_auth`(key/password)、`ssh_secret`、「启用 Agent 日常管理」`mgmt_enabled`;编辑且已配置时额外显示「测试连接 / 下发 frps 配置 / 查看服务端详情」。
|
|||
|
|
|
|||
|
|
合理之处:
|
|||
|
|
- 明确"首次安装/升级需 SSH,日常走 Agent API";SSH 仅用于生命周期与隧道。
|
|||
|
|
- 三个快捷操作按钮对编辑态友好。
|
|||
|
|
|
|||
|
|
问题:
|
|||
|
|
1. **`agent_url` placeholder 与实际安全模型冲突**:示例 `http://vps.example.com:7700`(525 行)鼓励公网明文 HTTP,而页面自身文案强调"不会默认暴露公网 7700"(244 行),且默认推荐 SSH 隧道 / HTTPS 固定。示例具有误导性。
|
|||
|
|
2. **SSH 字段无完整性校验**:填了 `ssh_host` 但缺 `ssh_user`/`ssh_secret`、或 `ssh_auth=key` 却粘贴密码时,无前端提示,失败延后到安装阶段。
|
|||
|
|
3. **`ssh_secret` 文案不随 `ssh_auth` 切换**:始终为"SSH 密码/私钥",用户需自行判断格式。
|
|||
|
|
4. **`mgmt_enabled=true` 但 `agent_url` 为空**的冲突组合无提示。
|
|||
|
|
5. **弹窗内「下发 frps 配置」(539 行)用的是已保存数据**:`pushAgentConfig(editingServer)` 以服务端 id 触发,后端按已存库配置生成;若用户在同一弹窗内刚改了 vhost/端口(尚未保存),点它下发的是**旧配置**,与"修改后需下发"的预期相悖。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、合理性问题清单(按优先级)
|
|||
|
|
|
|||
|
|
### P0(建议优先修复)
|
|||
|
|
|
|||
|
|
1. **「远程管理」帮助栏串台(明确缺陷)**
|
|||
|
|
- `serverHelpItems`(1307 行)只对 `advanced` 分支;`remote` 落入默认分支,展示的是**基础配置**的说明(基本信息/认证方式/frps 管理接口/描述)。
|
|||
|
|
- 帮助栏标题 `serverFormTab === 'basic' ? '配置说明' : '高级配置说明'`(601 行):`remote` 标签显示"高级配置说明"。
|
|||
|
|
- `serverHelpTip`(1323 行)对 `remote` 返回通用兜底文案。
|
|||
|
|
- 结果:用户在「远程管理」标签看到的右侧说明与其所在标签完全不符。
|
|||
|
|
|
|||
|
|
2. **表单无任何校验**(409、1603 行)
|
|||
|
|
- 无 `:model`/`:rules`;`saveServer` 直接提交。缺:名称/主机地址必填、端口有效、**创建时 token 认证令牌为空**、dashboard 成对、SSH 完整性、端口冲突等。
|
|||
|
|
|
|||
|
|
3. **`enabled` 字段无 UI 入口**
|
|||
|
|
- `serverForm.enabled` 在 reactive(1300 行)与 payload(1611 行)中存在,但**三个标签页均无绑定输入**,添加/编辑恒为 `true`。用户无法在表单中停用服务端。
|
|||
|
|
|
|||
|
|
### P1(影响体验/正确性)
|
|||
|
|
|
|||
|
|
4. 跨字段、跨标签冲突无校验(端口重复;`tls_force` ↔ `tls_enabled`;`sub_domain_host` 依赖)。
|
|||
|
|
5. 保存与"下发/重启"语义混用;弹窗内「下发 frps 配置」可能下发未保存前的旧配置。
|
|||
|
|
6. **过时文案**:多处提示"在「内网穿透」页服务端表单…填写"(244、310 行),但服务端表单已于 2026-09-24 迁入本页(AgentView),指引指向错误。
|
|||
|
|
7. `agent_url` 示例鼓励公网明文 HTTP,与页面安全模型矛盾。
|
|||
|
|
8. `dashboard_port`/`tcpmux` 的 0/空语义依赖文案,无强制。
|
|||
|
|
|
|||
|
|
### P2(可优化)
|
|||
|
|
|
|||
|
|
9. 「远程管理」混合了 frps 服务端参数、管理接口、Agent 接入三类关注点,标签命名与内容不符;建议拆分或重命名为"服务端与 Agent"。
|
|||
|
|
10. `defaultServerOptions()` 未覆盖远程标签字段,新增时 `undefined`,`n-switch`(`tls_force`/`frps_log_to_file`)可能收到 `undefined`。
|
|||
|
|
11. 高级标签用 collapse 收纳密集字段,远程标签 4 区块 ~18 字段平铺,密度管理不一致。
|
|||
|
|
12. `frps_log_max_days`(远程)与 `log_max_days`(高级/frpc)命名相近、分属不同标签,易混。
|
|||
|
|
13. `custom_404_page`、`allow_ports` 无格式校验。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、「远程管理」字段级对照表
|
|||
|
|
|
|||
|
|
| 字段(绑定) | 标签 | 控件 | 主要问题 | 建议 |
|
|||
|
|
| --- | --- | --- | --- | --- |
|
|||
|
|
| `options.vhost_http_port` | HTTP 回源端口 | number | 端口冲突未校验;无默认值 | 与相关端口做唯一性校验;补充默认值 |
|
|||
|
|
| `options.vhost_https_port` | HTTPS 回源端口 | number | 同上;`tls_force` 联动缺失 | 同上;联动 TLS 校验 |
|
|||
|
|
| `options.sub_domain_host` | 子域名根 | text | 依赖关系未提示 | 增加格式校验与说明 |
|
|||
|
|
| `options.tcpmux_http_connect_port` | tcpmux 监听端口 | number | "存在 tcpmux 规则时必填"无强制 | 按规则类型动态必填 |
|
|||
|
|
| `options.custom_404_page` | 自定义 404 页面 | text | 无路径校验 | 格式提示/后端预校验 |
|
|||
|
|
| `options.tls_force` | 强制 TLS | switch | 与 frpc `tls_enabled` 无联动 | 跨标签联动校验/提示 |
|
|||
|
|
| `options.frps_log_to_file` | frps 写文件日志 | switch | 默认 undefined | 纳入 defaultServerOptions |
|
|||
|
|
| `options.frps_log_max_days` | 日志保留天数 | number | 与 frpc `log_max_days` 易混 | 明确命名/分组 |
|
|||
|
|
| `options.allow_ports` | 端口白名单 | text | 无格式校验 | 正则校验 `\d+(-\d+)?(,\d+(-\d+)?)*` |
|
|||
|
|
| `options.max_ports_per_client` | 每客户端端口上限 | number | 0=不限需文案 | 保留,补 hint |
|
|||
|
|
| `options.dashboard_addr` | 管理地址 | text | 与 port 不成对校验 | 成对校验 |
|
|||
|
|
| `options.dashboard_port` | 管理端口 | number | 同上 | 成对校验 |
|
|||
|
|
| `options.dashboard_user` | 管理用户 | text | — | — |
|
|||
|
|
| `serverForm.dashboard_password` | 管理密码 | 密文 | — | — |
|
|||
|
|
| `serverForm.agent_url` | Agent API 地址 | text | 示例误导;无格式校验 | 改为隧道/HTTPS 示例;URL 校验 |
|
|||
|
|
| `serverForm.agent_token` | Agent Token | 密文 | — | — |
|
|||
|
|
| `serverForm.ssh_host` | SSH 地址 | text | 无完整性依赖校验 | 完整性校验 |
|
|||
|
|
| `serverForm.ssh_port` | SSH 端口 | number | — | — |
|
|||
|
|
| `serverForm.ssh_user` | SSH 用户 | text | 同上 | 完整性校验 |
|
|||
|
|
| `serverForm.ssh_auth` | SSH 认证 | select | 未联动 `ssh_secret` 文案 | 随选择切换文案/校验 |
|
|||
|
|
| `serverForm.ssh_secret` | SSH 密码/私钥 | 密文 | 同上 | 按认证方式校验格式 |
|
|||
|
|
| `serverForm.mgmt_enabled` | 启用 Agent 日常管理 | switch | 与 `agent_url` 空值冲突 | 联动提示 |
|
|||
|
|
| `serverForm.enabled` | (无标签) | 无 | **无 UI 入口** | 暴露或移除 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、改进建议
|
|||
|
|
|
|||
|
|
1. **修正帮助栏(低成本、高收益)**:为 `remote` 增加独立说明项集合;帮助栏标题改为按标签映射(如 `basic→配置说明 / advanced→高级配置说明 / remote→远程管理说明`)。
|
|||
|
|
2. **引入表单校验**:给 `<n-form>` 加 `:model` + `:rules`(或提交前手工校验),至少覆盖:名称/主机地址必填、端口范围、创建时 Token 认证必填、dashboard 成对、SSH 三件套完整、端口冲突、`allow_ports` 格式。
|
|||
|
|
3. **处理 `enabled`**:在基础配置补充"启用服务端"开关,或从表单与 payload 中移除。
|
|||
|
|
4. **跨字段联动**:`tls_force` ↔ `tls_enabled`、`ssh_auth` ↔ `ssh_secret`、`mgmt_enabled` ↔ `agent_url`、端口唯一性。
|
|||
|
|
5. **明确保存/生效语义**:保存后如涉及 frps 参数变更,给出"需下发并重启"的显式提示;或将「下发 frps 配置」改为先保存再下发,避免下发旧配置。
|
|||
|
|
6. **修正过时文案**:将"在「内网穿透」页服务端表单…"改为"本页表单…"(244、310 行)。
|
|||
|
|
7. **重排/重命名远程标签**:按"frps 服务端参数 / 可观测性(管理接口) / Agent 接入"折叠分组;标签可命名为"服务端与 Agent"。补齐 `defaultServerOptions()` 的远程字段默认值。
|
|||
|
|
8. **示例文案**:`agent_url` placeholder 改为 SSH 隧道本地地址或 HTTPS 固定示例,并注明不推荐公网明文。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、附:类型定义对照
|
|||
|
|
|
|||
|
|
`FrpServerOptions`(`web/src/api/types.ts` 395–450 行)中与「远程管理」相关的字段均已定义,并有中文注释(如 `tls_force` 注明"frpc 必须开 transport.tls.enable"、`dashboard_*` 注明"仅用于拉取只读信息")。前端表单字段与类型基本一致,主要缺口在**校验、默认值、帮助文案与字段归置**,而非类型缺失。
|
|||
|
|
|
|||
|
|
> 本文档为静态分析结论,具体以 `AgentView.vue` 源码为准;建议评审确认后再实施改动。
|