验证状态:已源码核验、未联调;适用基线:Web
7fe6dd10、services89bd222c;核验日期:2026-09-12
匿名上报前端缺失的 i18n 词条(key→value 草稿),供运营侧在翻译管理中补充。本操作是匿名可达端点(permitAll),只落 default 租户的待处理队列,不直接产生正式词条。App 接入时不应把它当作翻译读取或写入通道。
| 页面/功能 | 角色或空间分支 | 调用证据 |
|---|---|---|
| 缺失词条定时上报(30 秒周期) | 匿名可达;无需权限 | app/.client/components/missing-translation-reporter-1.tsx:3-24 |
| 后台 flush 分块发送(每请求 ≤500 键,每轮 ≤5 请求) | 同上 | app/.client/i18n/missing-translation-report-flush.ts:44-76 |
| 项 | 值 |
|---|---|
| operationId | http-post-main-service-system-api-configuration-translation-savemissing-7f257869 |
| method + path | POST /main-service/system-api/configuration/translation/saveMissing |
| base URL | 当前 Web 使用同源相对 URL |
| headers | Content-Type: application/json;无需 Authorization(permitAll) |
| 序列化 | body 由前端显式 JSON.stringify(translationPlusApi.ts:34-40) |
| 匿名放行 | application-default-es-center-server.yaml:207 "/system-api/configuration/translation/saveMissing"(SecurityConfig request-matchers) |
无需登录态(permitAll 放行,SecurityConfig.java:526-527 应用于 yaml 清单)。服务端忽略请求中的 tenantId:注释明示「匿名缺失上报只允许落 default 租户,调用方传来的任何 tenant 参数一律忽略」,强制 DEFAULT_TENANT_ID="default"(TranslationPlusController.java:29-30,64)。language 经服务端 languageMap 配置映射后再入队(TranslationPlusController.java:61-63)。
| JSON 路径/参数 | JSON 类型 | 位置 | 必填 | 可空 | 默认值 | 枚举/范围/单位 | 说明 | 字段证据 |
|---|---|---|---|---|---|---|---|---|
language |
string | query | 是 | 否 | 无 | @NotBlank |
语言;服务端按 languageMap 映射 |
TranslationPlusController.java:50-52 |
namespace |
string | query | 是 | 否 | 无 | @NotBlank |
命名空间 | 同上 |
tenantId |
string | query | 否 | 是 | 无(服务端忽略) | — | Web 仍发送(translationPlusApi.ts:25-32),服务端强制 default |
TranslationPlusController.java:29-30 |
| body | object | body | 是 | 否 | — | 键数 ≤500,超出返回 HTTP 400 | Map<String,String>:key→缺失时的原文值 |
TranslationPlusController.java:53-59 MAX_MISSING_TRANSLATIONS_PER_REQUEST |
| JSON 路径 | JSON 类型 | 出现条件 | 可空 | 枚举/范围/单位 | 说明 | 字段证据 |
|---|---|---|---|---|---|---|
timestamp/status/error/localizedError/path |
同信封 | JSON 响应 | — | — | 受理成功 status=200 |
gt-common-core/src/main/java/tech/gt/api/ApiResult.java |
extraData |
object | 成功 | 否 | — | 恒为 {} |
同上 |
data |
boolean | 受理成功 | 否 | true |
表示已入内存队列,非已落库 | TranslationPlusController.java:66 |
副作用链:enqueueMissing 写入内存队列(TranslationScheduling.java:80,Semaphore 容量 10000),由 TranslationScheduling 定时任务批量入库(每轮最多 20 批、最长等待 6 秒,TranslationScheduling.java:39-43,134)。
status=200 && data===true 表示服务端已受理入队(队列满员 10000 时例外:词条被静默丢弃而 ACK 不变,见错误与边界);词条何时落库、何时进入翻译视图均为异步,本操作不提供查询。Web 侧以该 ACK 为准删除本地快照(flush 脚本 :57-75),ACK 判定还要求 body 经 zod 校验为 {status:number, data:boolean}(translationPlusApi.ts:50-51)。
按已核验契约构造的示例,不是真实联调记录。
请求:POST /main-service/system-api/configuration/translation/saveMissing?language=zh-CN&namespace=translation&tenantId=default
成功响应:
超限失败(HTTP 400,键数 >500):
请求校验失败(@NotBlank);键数超限见上方 400 示例。Web 侧 10 秒超时(translationPlusApi.ts:14 SAVE_MISSING_TIMEOUT_MS),失败静默保留本地快照、不升级为全局页面错误(translationPlusApi.ts:33 注释与 flush 脚本 to() 包裹)。匿名端点无鉴权限流的源码证据;滥用上限仅受队列容量 10000 约束,满员后 enqueue 静默丢弃新词条(remainingCapacity.tryAcquire() 失败即返回,TranslationScheduling.java:103),调用方仍收到 200 && data=true——该 ACK 在满员场景下不代表词条已入队。
前端把待上报词条持久化在本地快照(missing-translation-report-store),30 秒周期 flush;只有收到受理 ACK 才删除对应快照。无服务端订阅资源。
入队满员(10000)时的行为已由源码核验为静默丢弃(见错误与边界);定时批量的落库时延在目标环境未联调核验。 仅完成双仓静态源码核验,未执行真实 HTTP 联调。
| 结论 | 状态 | 仓库/基线 | 路径、符号及定位 | 内容指纹(脏文件) |
|---|---|---|---|---|
| Web 方法、路径、序列化与消费 | 已源码核验 | web 7fe6dd10 |
translationPlusApi.ts:21-52;missing-translation-report-flush.ts:44-76;missing-translation-reporter-1.tsx:3-24 |
证据文件与 HEAD 一致 |
| 权限(匿名放行)与输入输出 | 已源码核验 | services 89bd222c |
TranslationPlusController.java:47-67;application-default-es-center-server.yaml:207 |
证据文件与 HEAD 一致 |
| 异步入库链 | 已源码核验 | services 89bd222c |
TranslationScheduling.java:37-46,80,134 |
证据文件与 HEAD 一致 |
| 真实部署联调 | 未执行 | — | 未发送请求 | — |