错误响应差异
HTTP status 与 JSON status 是两层。当前响应没有公共顶层 message;localizedError 也不保证非空。接口页必须链接实际适用的出口,不能按服务名或 @PreAuthorize 猜测。本页是全站错误出口的唯一正本;响应信封结构的通则演示见 API 域规范页(data-service、device-service),端点级错误事实以清单层与 Swagger 为准。
Security filter、entry point:认证拒绝
| 项 |
当前行为 |
| 触发 |
JWT 或认证异常,或未认证访问最终进入 entry point |
| HTTP / body status |
200 / 1000 |
| 字段 |
error 为认证常量;不本地化;不应有业务 extraData.message |
| 接入影响 |
HTTP 2xx 不代表认证成功;仍须按实际入口确认 |
Security denied handler:权限拒绝
| 项 |
当前行为 |
| 触发 |
权限失败最终交给 Security denied handler |
| HTTP / body status |
200 / 1001 |
| 字段 |
error 为权限常量;不本地化;不应有业务 extraData.message |
| 接入影响 |
传输状态为 2xx 时仍须解析业务状态 |
main ExceptionAdvice:认证与权限异常
| 项 |
当前行为 |
| 触发 |
MVC 边界捕获认证或权限异常 |
| HTTP / body status |
认证为 401 / 1000;权限为 403 / 1001 |
| 字段 |
error 为相应常量;尝试填充 localizedError,但可能为空 |
| 接入影响 |
与 Security filter 同一失败族的传输状态可能不同 |
device ExceptionAdvice:认证与权限异常
| 项 |
当前行为 |
| 触发 |
MVC 边界捕获认证或权限异常 |
| HTTP / body status |
200 / 1000 或 200 / 1001 |
| 字段 |
不填本地化;不应有业务 extraData.message |
| 接入影响 |
不可用 main Advice 的 HTTP 状态替代 device 行为 |
两服务 Advice:业务拒绝
| 项 |
当前行为 |
| 触发 |
ApiException,包括 Security filter 委托 Advice 的路径 |
| HTTP / body status |
200 / ex.status;默认,仅显式 null 时回退 |
| 字段 |
error=ex.getMessage,保留 extraData;main 尝试本地化,device 不填 |
| 接入影响 |
不能因异常发生在 filter 就把它归为认证失败 |
两服务 Advice:请求解析与校验
| 项 |
当前行为 |
| 触发 |
body 转换、参数绑定、Bean Validation 或 constraint violation |
| HTTP / body status |
400 / 1002、 或 |
| 字段 |
安全摘要;校验错误可聚合;main 尝试本地化 |
| 接入影响 |
保留响应 body 以支持字段提示,不能只展示 HTTP 400 |
两服务 Advice:路由与媒体类型
| 项 |
当前行为 |
| 触发 |
路径不存在、HTTP method 不支持或 Content-Type 不支持 |
| HTTP / body status |
404 / 1008、405 / 1006 或 415 / 1007 |
| 字段 |
固定协议摘要;main 尝试本地化 |
| 接入影响 |
不能用单一“非 200 即失败”规则抹平 body status 差异 |
Security filter 或 Advice:未处理技术异常
| 项 |
当前行为 |
| 触发 |
未处理技术异常 |
| HTTP / body status |
500 / 500 |
| 字段 |
error 为安全摘要;main Advice 尝试本地化,main filter 与 device 不填 |
| 接入影响 |
客户端需同时处理可解析业务 body 与非 JSON 网关失败 |
Agent API(/agent-api/v1/**):签名失败与脚本失败
| 项 |
当前行为 |
| 触发 |
query/header 签名缺失、过期、未来时间或 token 不匹配;或 handler 返回 AppError |
| HTTP / body status |
签名失败 401 / 401;内部失败 500 / 500(axum 按 envelope status 回写 HTTP status,common/api.rs:103-110) |
| 字段 |
Rust ApiResult 信封:error 为固定英文摘要("missing token or time"、"time window expired"、"invalid token"、"backup_failed: …" 等);path 填充请求路径;extra_data=null(serde 无 rename,wire 为 snake_case,与 Java 信封的 extraData 不同) |
| 接入影响 |
Agent 不接入中心账号体系,无 1000/1001 业务码族;能构造签名的客户端即可调用 |
Meilisearch 代理:上游错误透传
| 项 |
当前行为 |
| 触发 |
上游 Meilisearch 返回非 2xx(RestClientResponseException),或代理自身异常 |
| HTTP / body status |
经 main Advice 业务拒绝出口:HTTP,body status = 上游 HTTP 状态码(显式 setStatus);代理自身异常为 200 / 500 |
| 字段 |
error="Meilisearch proxy error: {上游消息}" 或 "Proxy error: …";注意检索成功响应不走 {status,data} 信封(原样字节流) |
| 接入影响 |
status 值域是上游 HTTP 码(404/400 等),不是 1000/422 族业务码;须按上游 API 语义解释 |
以上为当前实现差异,不是未来统一目标。无效或缺失 token 是否立即得到 取决于过滤链和白名单,不能一概而论。
依据
适用后端基线:源码归纳 @ 2026-09-14(Agent 信封与 Meilisearch 代理两行由整合票 20 于 2026-09-12 复核)。
| 出口 |
源码定位 |
| 认证拒绝、权限拒绝 |
main config/SecurityConfig.usernamePasswordAuthenticationFilter:433–449、、;device 同名符号 、 |
| main Advice |
main controller/ExceptionAdvice.authenticationExceptionHandler:72–93 |
| device Advice |
device controller/ExceptionAdvice 认证/权限 handlers |
| 业务拒绝 |
main ExceptionAdvice.apiExceptionHandler:232–236、filter;device Advice 、filter |
| 请求校验、路由与媒体类型 |
main;device |
| 技术异常 |
main filter 、Advice;device filter 、Advice |
| Agent 签名与信封 |
es-center-server-agent config/app.rs:150–195(401 出口)、common/api.rs:26–110(信封与 HTTP status 回写)、common/app_error.rs:39–48(AppError→信封) |
| Meilisearch 代理透传 |
保留上游 HTTP 状态码(经统一异常出口),经 main Advice 业务拒绝出口 |
认证和权限的状态码语义为源码归纳结论。每个操作仍须从自身入口链确认实际落到哪个出口。Agent 信封差异由票 16 四页与整合票 20 复核后合并;Meilisearch 代理出口依据票 16 枚举日志检索索引 正本。