添加客户端特殊标识 #226
Notifications
Total Time Spent: 15 seconds
kdletters
15 seconds
Depends on
#241 AGC对主站的请求添加header
GenarrativeAI/Genarrative
Reference: GenarrativeAI/Genarrative#226
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
打算怎么做,修改范围是哪些
AGC 主站请求标记统一注入两种方案
更新时间:2026-09-01
关联 Issue:
#226 添加客户端特殊标识、#225 添加客户端埋点统计状态:方案说明,未实施代码修改
1. 背景
AGC 客户端同时存在两套 HTTP 出口:
fetchClientHttp使用浏览器fetch或 Tauri HTTP 插件。reqwest::Client直接调用主站、对象存储、签名下载地址、LLM Provider 和本地工具桥。目标是让 AGC 发往主站的请求统一携带来源标记,而不是在每个业务 API 调用点重复写 Header。
推荐标记:
该标记只用于来源审计、埋点和统计,不参与鉴权、权限、计费或账号归属判断。
2. 目标与不做项
2.1 目标
/api/...调用点重复设置 Header。2.2 不做项
#225。reqwest请求无差别设置默认 Header。3. 两种方案的共同部分
无论 Rust 层选择哪种方案,Web/TS 层都可以直接在统一出口注入。
3.1 Web/TS 统一出口
文件:
处理方式:
fetchClientHttp解析最终请求地址。serverBaseUrl。fetch或 Tauri HTTP 插件前设置:示意代码:
需要保留调用方原有 Header,尤其是:
AuthorizationContent-Typex-genarrative-response-envelopeX-Request-ID,如果调用方已提供3.2 主站 origin 的定义
不能只写死以下两个地址:
AGC 还支持自定义服务器,判断依据应是当前请求绑定的权威
serverBaseUrl/apiBaseUrl,并比较规范化后的 origin:路径、query 和 fragment 不属于 origin 判断条件。
3.3 必须排除的请求
以下请求不能携带主站客户端标记:
direct-upload-tickets返回的对象存储 multipart 上传地址。read-url返回的临时签名下载地址。/responses等请求。3.4 CORS
浏览器环境向不同 origin 的主站发送自定义 Header 时可能触发 CORS 预检。主站及自定义部署需要允许:
Tauri HTTP 插件和 Rust
reqwest不受浏览器 CORS 限制,但仍应遵守相同的目标 origin 边界。4. 方案一:专用主站 HTTP Client 工厂
4.1 核心思路
为 Rust 层建立一个只允许服务于主站 API 的
reqwest::Client构造函数,并通过default_headers自动加入客户端标记。第三方上传、签名下载、Provider 和搜索继续使用现有独立 Client,不带标记。
示意代码:
调用代码仍然保持普通
reqwest写法:业务请求不再逐个调用
.header("X-Genarrative-Client", "agc")。4.2 预计改动范围
主要改动是把主站用途的
reqwest::Client::new()/Client::builder()替换为统一工厂,而不是修改每个 API endpoint。潜在涉及文件:
不应迁移到主站 Client 的文件或请求:
build_external_asset_download_client创建的签名资源下载 Client。4.3 优点
4.4 缺点和风险
default_headers对该 Client 发出的所有请求生效,不会再次判断目标域名。4.5 风险控制
保持控制简单,不引入复杂网络状态机:
apiBaseUrl的模块中创建。build_external_asset_download_client单独创建。main_site,避免误用。5. 方案二:按目标 origin 的请求包装器
5.1 核心思路
不依赖 Client 的默认 Header,而是统一通过一个请求构造入口创建主站 RequestBuilder。
包装器在构造请求时:
apiBaseUrl。更安全的做法是主站包装器直接拒绝非同源 URL。
示意代码:
调用示意:
5.2 预计改动范围
所有主站
.get(...)、.post(...)、.patch(...)、.delete(...)构造点需要切换为包装器,或统一封装为一个AgcMainSiteHttp类型。例如:
下载、OSS 和 Provider 请求继续直接使用普通
reqwest::Client。5.3 优点
5.4 缺点和风险
ExternalEditorBindingAccess、路由映射、冻结会话校验等概念,再新增完整 HTTP facade 会增加概念数量。5.5 风险控制
ExternalEditorBindingAccess继续负责账号态/开发者 Key 路由映射和冻结会话校验。6. 两种方案对比
reqwest::Client::default_headers7. 推荐选择
当前推荐 方案一:专用主站 HTTP Client 工厂。
理由:
方案一需要明确遵守:主站 Client 不能用于签名下载、OSS 上传和 Provider 请求。如果实施时发现多个模块无法可靠维持这条边界,或存在大量由外部数据生成的动态目标 URL,再改选方案二。
不建议一开始同时实现两种方案。二选一即可,避免形成“Client 默认 Header + RequestBuilder 再加一次 Header”的重复机制。
8. 建议的 PR 边界
8.1
#226 添加客户端特殊标识负责:
fetchClientHttp统一注入标记。不负责:
8.2
#225 添加客户端埋点统计负责:
ExternalApiPrincipal记录认证主体。tracking_event.metadata_json或后续确定的结构化字段。/api/external/v1/*tracking。9. 验收清单
9.1 正向请求
X-Genarrative-Client: agc。/api/editor/*请求带标记。/api/assets/*请求带标记。/api/runtime/external-generation/jobs/*轮询带标记。/api/external/v1/*请求带标记。/api/profile/api-keys请求带标记。9.2 排除请求
9.3 兼容性
X-Genarrative-Client。看过现状后建议把 #226 收敛一下。
Header 注入本身确实简单:TS 侧已有统一出口 fetchClientHttp,在这里用 new Headers(init.headers) 后设置 X-Genarrative-Client: agc 即可,并保留调用方现有 Authorization、Content-Type、幂等键等 Header。
Rust 侧不能给进程内所有 reqwest::Client 无差别加默认 Header。当前 client 分别服务于主站、OSS/签名资源下载、LLM Provider、受控搜索和 loopback 工具桥,且 timeout、redirect、proxy 等策略不同;全局注入会把主站标记泄漏到第三方。
本 Issue 的实现范围建议定为:
方案二的 origin wrapper 可以留作后续增强,当前没有必要为一个固定 Header 新增完整 HTTP facade。CORS 服务端配置、接收落库和后台统计也请保持在服务端/#225 的边界内。建议先按上述范围实施并提 PR,避免继续在 Issue 里并列两套方案和展开完整设计文档。