| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package service
- import "time"
- // UserErrorRequest 是面向终端用户的"错误请求"精简脱敏视图(白名单)。
- // 严禁包含 account / api_key_prefix / upstream_endpoint / user_email 等
- // 敏感或内部字段。注:message(网关标准化错误描述)与 key_name
- // (用户自有 API Key 名称,KeysView 中本就可见)经产品决策对该用户开放;
- // client_ip / user_agent / group_name / request_type / stream 均为该用户
- // 自己请求的属性,经产品决策(2026-07-03)开放,
- // 与用量明细已向用户展示自身 ip_address/user_agent/分组/类型 的口径对齐;
- // error_body 仅在详情接口(GetUserErrorRequestDetail)按归属校验后返回。
- type UserErrorRequest struct {
- ID int64 `json:"id"`
- CreatedAt time.Time `json:"created_at"`
- Model string `json:"model"`
- InboundEndpoint string `json:"inbound_endpoint"`
- StatusCode int `json:"status_code"`
- Category string `json:"category"`
- Platform string `json:"platform"`
- Message string `json:"message"`
- KeyName string `json:"key_name"`
- KeyDeleted bool `json:"key_deleted"`
- ClientIP string `json:"client_ip,omitempty"`
- GroupName string `json:"group_name,omitempty"`
- RequestType *int16 `json:"request_type,omitempty"`
- Stream bool `json:"stream"`
- UserAgent string `json:"user_agent,omitempty"`
- }
- // UserErrorRequestList 是用户错误请求分页结果。
- type UserErrorRequestList struct {
- Items []*UserErrorRequest `json:"items"`
- Total int `json:"total"`
- Page int `json:"page"`
- PageSize int `json:"page_size"`
- }
- // MapUserErrorCategory 把后端 error_phase + error_type 映射为用户侧粗分类码。
- // 返回的是稳定的分类 code(前端做 i18n),不是展示文案。
- func MapUserErrorCategory(phase, errType string) string {
- switch phase {
- case "auth":
- return "auth"
- case "routing":
- return "service_unavailable"
- case "account_auth", "upstream", "network":
- return "upstream"
- case "internal":
- return "internal"
- case "request":
- switch errType {
- case "rate_limit_error":
- return "rate_limit"
- case "billing_error", "subscription_error":
- return "quota"
- case "invalid_request_error":
- return "invalid_request"
- case "cyber_policy":
- return "cyber"
- }
- }
- return "other"
- }
- // CategoryToFilter 把用户侧分类码反向映射为后端过滤条件(plain ANY)。
- // 未知分类返回两个空切片(即不施加分类过滤)。
- // 注意:"other" 与未知分类都走 default 返回空切片——"other" 无对应的 phase/type 组合,无法精确反查,因此等价于不过滤。
- func CategoryToFilter(category string) (phases []string, errorTypes []string) {
- switch category {
- case "auth":
- return []string{"auth"}, nil
- case "service_unavailable":
- return []string{"routing"}, nil
- case "upstream":
- return []string{"account_auth", "upstream", "network"}, nil
- case "internal":
- return []string{"internal"}, nil
- case "rate_limit":
- return nil, []string{"rate_limit_error"}
- case "quota":
- return nil, []string{"billing_error", "subscription_error"}
- case "invalid_request":
- return nil, []string{"invalid_request_error"}
- case "cyber":
- return []string{"request"}, []string{"cyber_policy"}
- default:
- return nil, nil
- }
- }
- // ToUserErrorRequest 把内部 OpsErrorLog 裁剪为用户安全视图。
- func ToUserErrorRequest(e *OpsErrorLog) *UserErrorRequest {
- if e == nil {
- return nil
- }
- model := e.RequestedModel
- if model == "" {
- model = e.Model
- }
- clientIP := ""
- if e.ClientIP != nil {
- clientIP = *e.ClientIP
- }
- return &UserErrorRequest{
- ID: e.ID,
- CreatedAt: e.CreatedAt,
- Model: model,
- InboundEndpoint: e.InboundEndpoint,
- StatusCode: e.StatusCode,
- Category: MapUserErrorCategory(e.Phase, e.Type),
- Platform: e.Platform,
- Message: e.Message,
- KeyName: e.APIKeyName,
- KeyDeleted: e.APIKeyDeleted,
- ClientIP: clientIP,
- GroupName: e.GroupName,
- RequestType: e.RequestType,
- Stream: e.Stream,
- UserAgent: e.UserAgent,
- }
- }
- // UserErrorRequestDetail 是错误请求详情的脱敏视图(点击单行查看)。
- // 在 UserErrorRequest 基础上额外暴露 error_body(上游错误响应正文)与 upstream_status_code;
- // 仍严禁任何内部/敏感字段。
- type UserErrorRequestDetail struct {
- UserErrorRequest
- ErrorBody string `json:"error_body"`
- UpstreamStatusCode *int `json:"upstream_status_code,omitempty"`
- }
- // ToUserErrorRequestDetail 把内部 OpsErrorLogDetail 裁剪为用户安全详情视图。
- func ToUserErrorRequestDetail(e *OpsErrorLogDetail) *UserErrorRequestDetail {
- if e == nil {
- return nil
- }
- base := ToUserErrorRequest(&e.OpsErrorLog)
- return &UserErrorRequestDetail{
- UserErrorRequest: *base,
- ErrorBody: e.ErrorBody,
- UpstreamStatusCode: e.UpstreamStatusCode,
- }
- }
|