Files
freedak f7a720204a Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
2026-07-04 19:20:46 +08:00

184 lines
13 KiB
Markdown
Raw Permalink 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.
# API 概览
NomiFun 的后端(`nomifun-app`,二进制 `nomicore`)对外暴露的是单一的
axum HTTP 服务。SPA、桌面外壳,以及任何外部集成,与它沟通的方式都一样:
HTTP 上的 JSON 用于命令/查询,WebSocket 用于流式事件。
本页是一份**导览**,不是穷尽式的端点参考。完整的接口面位于
`crates/backend/` 下的各路由模块;源码即权威参考。下方列出了各分组的
基础路径与对应的路由 owner——请从那里开始查阅。
## Base URL
| 宿主 | 默认 base URL | 备注 |
|---|---|---|
| `nomifun-desktop` | `http://127.0.0.1:<picked-port>` | 启动时挑选一个空闲的 localhost 端口。渲染端通过 IPC 获知端口号,并以此向 `/api``/ws` 发起调用。 |
| `nomifun-web` | `http://<host>:<port>`(默认 `http://127.0.0.1:8787`) | 同一个后端,与 SPA 一并在同一个端口上提供。 |
| `nomicore` 独立运行 | `http://127.0.0.1:25808` | 单独运行后端——便于调试。 |
SPA 使用**相对路径**`/api/...``/ws`)。客户端不需要指向另一台 API
服务——SPA 与 API 同址。
## 鉴权模型
NomiFun 启动时进入三种鉴权策略之一:
### 已鉴权模式(`nomifun-web` 默认)
- 通过 `POST /login` 登录,返回一个会话 JWT,同时写入 cookie
`nomifun-session``HttpOnly`)与 JSON body。后续请求依靠该 cookie
`Authorization: Bearer …` 请求头进行鉴权。
- 状态变更类请求还必须附带 CSRF 请求头 `x-csrf-token`,其值需与
`nomifun-csrf-token` cookie 匹配(Double Submit Cookie 模式)。安全
方法(`GET``HEAD``OPTIONS`)跳过 CSRF;登录/设置/二维码登录端点
因尚无会话被豁免。
- WebSocket 升级携带同一份 JWT——通常通过 `Sec-WebSocket-Protocol`
传输,可由 `GET /api/ws-token` 获取。`/ws` 路由对 CSRF 豁免(在
WebSocket 升级中无法做基于 cookie 的双提交),但仍需鉴权。
- 限流器分别按客户端作用于登录尝试、一般 API 流量与已鉴权的状态变更
动作。
### 桌面本地信任模式(`nomifun-desktop`
- 嵌入式后端使用 `AuthPolicy::TrustLocalToken`
- 桌面 WebView 会得到每次启动生成的 secret(`window.__nomiLocalTrust`),并在 HTTP/WebSocket 请求中呈递它。
- 其他客户端即使在同一台机器上,也不会因为来自 loopback 自动受信任;除非它拥有正常登录会话。这也是 WebUI 远程访问可以放在登录后的原因。
### 无鉴权本地模式(`nomicore --local`,或 Web 宿主 `--insecure-no-auth`
- 鉴权与 CSRF 完全关闭。每个请求都以 `system_default_user` 身份执行。
- 加入一层宽松的 CORS,使桌面 WebView(以及工具)可以自由调用 API。
- 仅本地可达的路由(如 `/api/auth/internal/*``/api/webui/*`)变为
可达。
本地模式下的信任边界是网络——只能将其暴露在 loopback 或完全受信任的
私有网络上。Web 宿主在 `--insecure-no-auth` 与非 loopback 绑定同时使用
时会大声地打印警告日志。
## 请求体大小与上限
- 请求体的默认大小上限是 **10 MiB**`nomifun-common` 中的
`BODY_LIMIT`)。确实需要更大的路由(文件上传、ZIP 创建等)会安装自己
的更大限制——`/api/fs/upload` 接受最大 30 MiB。
- 代用户下载的远程图片上限为 5 MiB,最多跟随 5 次重定向。
## 路由分组
每个分组归属一个特定的 crate。下表中的基础路径就是挂载到 app router 中
的实际 URL 前缀;鉴权在已鉴权模式和桌面本地信任模式下生效。
| 分组 | 基础路径 | 鉴权 | 归属 crate / 文件 |
|---|---|---|---|
| 健康检查 | `/health` | 公共 | [`router/health.rs`](../../crates/backend/nomifun-app/src/router/health.rs) |
| 鉴权 —— 登录 / 设置 / 状态 / 刷新 | `/login``/logout``/api/auth/*``/api/ws-token``/qr-login` | 混合(登录/设置/qr-login:公共;其余:已鉴权) | [`nomifun-auth/src/routes.rs`](../../crates/backend/nomifun-auth/src/routes.rs) |
| 鉴权 —— 仅本地 admin/internal | `/api/webui/*``/api/auth/internal/*` | 仅本地模式 | 同上 |
| 会话 | `/api/conversations/*``/api/messages/search` | 已鉴权 | [`nomifun-conversation/src/routes.rs`](../../crates/backend/nomifun-conversation/src/routes.rs)、[`routes_aux.rs`](../../crates/backend/nomifun-conversation/src/routes_aux.rs) |
| 智能体(本地 CLI 智能体) | `/api/agents/*` | 已鉴权 | [`nomifun-ai-agent/src/routes/agent.rs`](../../crates/backend/nomifun-ai-agent/src/routes/agent.rs) |
| 远程智能体 | `/api/remote-agents/*` | 已鉴权 | [`nomifun-ai-agent/src/routes/remote.rs`](../../crates/backend/nomifun-ai-agent/src/routes/remote.rs) |
| 助手 | `/api/assistants/*` | 已鉴权 | [`nomifun-assistant/src/routes.rs`](../../crates/backend/nomifun-assistant/src/routes.rs) |
| 助手标签 | `/api/assistant-tags/*` | 已鉴权 | 同上 |
| MCP 服务 | `/api/mcp/*` | 已鉴权 | [`nomifun-mcp/src/routes.rs`](../../crates/backend/nomifun-mcp/src/routes.rs) |
| 技能 | `/api/skills/*` | 已鉴权 | [`nomifun-extension/src/skill_routes.rs`](../../crates/backend/nomifun-extension/src/skill_routes.rs) |
| 扩展 | `/api/extensions/*` | 已鉴权 | [`nomifun-extension/src/routes.rs`](../../crates/backend/nomifun-extension/src/routes.rs) |
| Hub(扩展市场) | `/api/hub/*` | 已鉴权 | [`nomifun-extension/src/hub_routes.rs`](../../crates/backend/nomifun-extension/src/hub_routes.rs) |
| 计划任务 | `/api/cron/*` | 已鉴权 | [`nomifun-cron/src/routes.rs`](../../crates/backend/nomifun-cron/src/routes.rs) |
| 频道(IM 桥) | `/api/channel/*` | 已鉴权 | [`nomifun-channel/src/routes.rs`](../../crates/backend/nomifun-channel/src/routes.rs) |
| Webhook + 标签设置 | `/api/webhooks/*``/api/tags/{tag}/settings` | 已鉴权 | [`nomifun-webhook/src/routes.rs`](../../crates/backend/nomifun-webhook/src/routes.rs) |
| 需求(项目看板) | `/api/requirements/*` | 已鉴权 | [`nomifun-requirement/src/routes.rs`](../../crates/backend/nomifun-requirement/src/routes.rs) |
| AutoWork / IDMM | `/api/idmm/*``/api/requirements/autowork*` | 已鉴权 | [`nomifun-idmm/src/routes.rs`](../../crates/backend/nomifun-idmm/src/routes.rs) |
| 团队(后端实现面;当前没有对应用户指南路由) | `/api/teams/*` | 已鉴权 | [`nomifun-team/src/routes.rs`](../../crates/backend/nomifun-team/src/routes.rs) |
| 终端 | `/api/terminals/*` | 已鉴权 | [`nomifun-terminal/src/routes.rs`](../../crates/backend/nomifun-terminal/src/routes.rs) |
| 终端 knowledge 注册辅助 | `/api/terminals/mcp-register-template``/api/terminals/register-knowledge*``/api/terminals/knowledge-global-status` | 已鉴权 | [`router/health.rs`](../../crates/backend/nomifun-app/src/router/health.rs) |
| 知识库 | `/api/knowledge/*` | 已鉴权 | [`nomifun-knowledge/src/routes.rs`](../../crates/backend/nomifun-knowledge/src/routes.rs) |
| 伙伴 | `/api/companion/*` | 已鉴权 | [`nomifun-companion/src/routes.rs`](../../crates/backend/nomifun-companion/src/routes.rs) |
| WebUI/public 能力 companion token | `/api/webui/companions/{id}/access-token` | 已鉴权 / 本地 WebUI admin 流 | [`router/companion_token_routes.rs`](../../crates/backend/nomifun-app/src/router/companion_token_routes.rs) |
| Browser-use secrets | `/api/browser-secrets/*` | 已鉴权 | [`nomifun-secret/src/routes.rs`](../../crates/backend/nomifun-secret/src/routes.rs) |
| 文件系统 | `/api/fs/*` | 已鉴权 | [`nomifun-file/src/routes.rs`](../../crates/backend/nomifun-file/src/routes.rs) |
| Office 预览 | `/api/word-preview/*``/api/excel-preview/*``/api/ppt-preview/*``/api/document/convert``/api/preview-history/*``/api/star-office/detect` | 已鉴权 | [`nomifun-office/src/routes.rs`](../../crates/backend/nomifun-office/src/routes.rs) |
| Office iframe 代理 | `/api/ppt-proxy/*``/api/office-watch-proxy/*` | 公共(提供 iframe 内容;不鉴权) | 同上 |
| 设置 + 提供商 + 系统信息 | `/api/settings``/api/providers/*``/api/system/*` | 已鉴权 | [`nomifun-system/src/routes.rs`](../../crates/backend/nomifun-system/src/routes.rs) |
| 全局模型故障转移队列 | `/api/agent/model-failover` | 已鉴权 | [`router/model_failover.rs`](../../crates/backend/nomifun-app/src/router/model_failover.rs) |
| 连接探测(Bedrock 等) | `/api/bedrock/test-connection` | 已鉴权 | [`nomifun-system/src/bedrock_probe/routes.rs`](../../crates/backend/nomifun-system/src/bedrock_probe/routes.rs) |
| Shell 辅助 + STT | `/api/shell/*``/api/stt` | 已鉴权 | [`nomifun-shell/src/routes.rs`](../../crates/backend/nomifun-shell/src/routes.rs) |
| 公共资源(logo | `/api/assets/logos/*` | 公共 | [`nomifun-assets/src/routes.rs`](../../crates/backend/nomifun-assets/src/routes.rs) |
| Public MCP front door | `/mcp/*` | companion-token / 已配置 public auth | [`nomifun-public/src/router.rs`](../../crates/backend/nomifun-public/src/router.rs) |
| Public MCP agent front door | `/mcp-agent/*` | companion-token / 已配置 public auth | [`nomifun-public/src/router.rs`](../../crates/backend/nomifun-public/src/router.rs) |
| Remote capability REST API | `/v1/*` | companion-token | [`nomifun-public/src/rest.rs`](../../crates/backend/nomifun-public/src/rest.rs) |
| 实时 WebSocket | `/ws` | 已鉴权(token 通过 `Sec-WebSocket-Protocol` 或查询串传递) | [`nomifun-realtime/src/handler.rs`](../../crates/backend/nomifun-realtime/src/handler.rs) |
如需各路由具体支持的方法,请阅读对应的 `routes.rs` 文件——每个 router
都在源文件内联声明自身的路由。
### 选取的鉴权端点
下面这些是客户端最常直接交互的鉴权端点:
| 方法 + 路径 | 用途 |
|---|---|
| `POST /login` | 用户名 + 密码登录。返回 `{success, user, token}` 并设置会话 cookie。CSRF 豁免。带限流。 |
| `POST /api/auth/setup` | 全新安装上的一次性首位管理员创建。原子操作;并发调用通过条件 UPDATE 竞争,只有一个会赢(其余得到 `409 Conflict`)。CSRF 豁免。 |
| `POST /logout` | 将当前 token 加入黑名单;清除会话 cookie。 |
| `GET /api/auth/status` | 公共——返回 `{needs_setup, user_count, is_authenticated}`。可作为 liveness/health 探针。 |
| `GET /api/auth/user` | 返回当前 `{id, username}`。 |
| `POST /api/auth/change-password` | 修改当前用户密码并轮换 JWT 密钥(使其他会话全部失效)。 |
| `POST /api/auth/refresh` | 刷新仍然有效但接近过期的 token。 |
| `GET /api/ws-token` | 返回用于 WebSocket 升级的 token。 |
| `POST /api/auth/qr-login` | 消费一次性的二维码登录 token(由 WebUI 远程访问流程下发)。 |
| `GET /qr-login` | 静态 HTML 页面,用于完成来自手机扫码的二维码登录跳转。 |
## WebSocket 事件模型
`/ws` 是用于流式更新的单一双向通道:智能体 token 流、终端输出,
需求/计划任务/团队的状态变化等等。
- 鉴权:通过 `GET /api/ws-token` 获得的 JWT,放在 WebSocket 的
`Sec-WebSocket-Protocol` 请求头中(或 `Authorization`)。token 无效或
过期 → 服务端发出 `auth-expired` 事件并以 `1008` 关闭。完全没有
token → 以 `1008` 关闭,原因为 `"no token provided"`
- 升级成功后,每条消息都是带 `type``payload` 的 JSON 对象。当域内
事件发生时(新的智能体 token、一个终端字节、需求状态切换),由
服务端推送;客户端通常无需回送任何内容。服务端把单一的
`BroadcastEventBus` 多路复用给所有已连接客户端。
- 心跳:每 30 秒 ping 一次,60 秒超时(`HEARTBEAT_INTERVAL_MS` /
`HEARTBEAT_TIMEOUT_MS`)。
- 关闭码:`1000` 表示正常关闭;`1008` 表示策略违规(鉴权失败、token
无效)。
`type` 取值集合是开放的——扩展与功能模块会发出各自的类型。请把未知
类型当作向前兼容的:忽略它们即可。
## 响应包络
绝大多数 JSON 响应使用同一种形状(来自 `nomifun-api-types`
`ApiResponse<T>`):
```json
{ "success": true, "data": { ... } }
```
错误使用恰当的 HTTP 状态码返回,body 形如:
```json
{ "success": false, "error": "Invalid username or password" }
```
登录/设置/刷新这几个 handler 会返回略微富化的包络
`LoginResponse``RefreshResponse`)——它们会把 token 或 user 对象
内联在响应中。
## 真值来源指引
上面的列表只是为了把你引导到对的模块。到达后请阅读源码——每个 router
在一处声明全部路由,每个 handler 都在同一个文件或紧挨着的下一个文件
里。Router 装配本身位于
[`crates/backend/nomifun-app/src/router/routes.rs`](../../crates/backend/nomifun-app/src/router/routes.rs)
中间件栈(CSRF、安全响应头、请求体上限、可选的 CORS)也在那里。
## 另见
- [配置参考](./configuration.zh.md) —— 参数、环境变量、鉴权密钥解析顺序。
- [疑难排查](./troubleshooting.zh.md) —— 常见的 API 与 WebSocket 故障
形态。
- [Web 服务部署](../guides/web-server-deployment.md) —— 在 TLS 之后把
API 暴露到网络上。