docs(cors): X-API-Version 明确为 advisory 惯例头(E1) — 消除版本协商假象
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- middleware: CORS Allow-Headers 加 X-API-Version(跨域客户端不再预检失败)
- api-reference §0.2 + api-client §4.1: 声明服务端不校验、不据此协商版本
- 后端/前端零行为改动(前端仍在发,现CORS放行)
This commit is contained in:
AskaEth committed 2026-09-08 21:24:36 +08:00
1 parent 99f222761e
commit 3fc10fb86f
3 files changed
+4 -4

No files matched your search

+1 -1
View File
@@ -183,7 +183,7 @@
### 4.1 一次性接入流程(三步走)
1. **拿令牌**:`POST /api/v1/auth/login` `{username,password}` → `{data:{token,expiresAt,role}}`(JWT,默认 24h,`role` ∈ `owner|admin|viewer`)。
2. **声明版本**:后续每个请求头带上 `X-API-Version: 1` + `Authorization: Bearer <token>`;WS 握手用 `ws://<host>:<port>/ws/chat?token=<token>`(或 `Authorization: Bearer`)。**viewer 只能读会话/人格元数据;读写会话消息、管理写操作需 `owner`/`admin`。**
2. **声明版本(可选/advisory)**:可带 `X-API-Version: 1` + `Authorization: Bearer <token>`;WS 握手用 `ws://<host>:<port>/ws/chat?token=<token>`(或 `Authorization: Bearer`)。**`X-API-Version` 是**advisory**惯例头——服务端当前不校验、不据此协商版本,带不带行为不变**;`viewer` 只能读会话/人格元数据;读写会话消息、管理写操作需 `owner`/`admin`。
3. **带端标识**(可选但推荐):每条消息/请求可带 `deviceId`(见 §4.3),让她知道你从哪个端来。
### 4.2 会话与消息用法(聊天)
+2 -2
View File
@@ -15,7 +15,7 @@
- 成功:`{"data": <payload>}`(HTTP 200 / 201 / 202 / 204)。
- 失败:`{"error": {"code": <string>, "message": <string>}}`(HTTP 400/401/403/404/409/500/501 等)。
- **错误码**:业务错误带稳定字符串 `code`(如 `unauthorized` / `not_found` / `bad_request` / `chat_busy` / `not_implemented`),便于客户端分支;`message` 面向人读。
- **CORS**:`Access-Control-Allow-Origin` 为配置的 `ALLOWED_ORIGINS` 白名单(`*` 时放开);`Allow-Methods: GET, POST, PUT, DELETE, OPTIONS`;`Allow-Headers: Authorization, Content-Type`;`Access-Control-Expose-Headers: X-Voice-Provider`(让跨域浏览器能读到该语音降级信号头,非跨域场景不受影响);`Max-Age: 600`。`OPTIONS` 预检直接回 `204`。同源/无 Origin 请求放行。**注意:CORS 只允许 `Authorization, Content-Type` 头——若客户端要额外发送 `X-API-Version`,需自行在网关侧放开或仅作为文档惯例(当前服务端**不校验**该头)。**
- **CORS**:`Access-Control-Allow-Origin` 为配置的 `ALLOWED_ORIGINS` 白名单(`*` 时放开);`Allow-Methods: GET, POST, PUT, DELETE, OPTIONS`;`Allow-Headers: Authorization, Content-Type, X-API-Version`;`Access-Control-Expose-Headers: X-Voice-Provider`(跨域浏览器可读语音降级信号头);`Max-Age: 600`。`OPTIONS` 预检直接回 `204`。同源/无 Origin 请求放行。**注意:`X-API-Version` 仅作**advisory**惯例头(见 §0.2)——CORS 已放行但它**不参与服务端版本协商**,服务端当前不校验、不据此改变行为。**
- **请求日志**:每个请求由 `logging` 中间件记录一行(method/path/status/duration_ms),并计入可观测性指标。panic 由 `recover` 中间件兜底为 `500 {error:{code:internal,...}}`,不崩溃进程。
- **超时**:WS 连接 ping 周期 54s、pong 等待 60s、写超时 10s;读上限 4096 字节/帧。
@@ -34,7 +34,7 @@
### 0.2 X-API-Version 头
`Docs/api-client.md` 约定客户端每个请求带 `X-API-Version: 1`。**当前服务端不校验该头**(未在代码中读取),仅作为客户端契约惯例;如需服务端强校验,需另行实现。本文档在 curl 示例中**带上该头**以示惯例。
`Docs/api-client.md` 建议客户端可带 `X-API-Version: 1`。**该头是 advisory 惯例头——服务端不校验、不据此协商版本,带不带行为完全不变**(`CORS Allow-Headers` 已放行它,跨域客户端发送不会预检失败)。若未来要真正版本化(`/api/v1` → 语义化协商),需另行实现服务端校验;在那之前客户端不应依赖它做任何行为分支。
### 0.3 上传 / 媒体(重要确认)
+1 -1
View File
@@ -24,7 +24,7 @@ func (s *Server) cors(next http.Handler) http.Handler {
}
w.Header().Set("Vary", "Origin")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-API-Version")
w.Header().Set("Access-Control-Expose-Headers", voiceProviderHeader)
w.Header().Set("Access-Control-Max-Age", "600")
}