fix(errors): 区分平台限流并保留上游状态码
原因:公开错误层将平台并发限流误标为上游限流,并把多种上游 4xx 统一压成 400,影响定位和客户端处理。 影响:新增公开错误 source,平台限流使用 gateway_rate_limited,上游请求按安全分类返回对应状态;数据库与管理端继续保留原始错误码、消息和状态用于审计。 验证:Go 全量测试、pnpm test、pnpm lint、pnpm build、pnpm openapi、gofmt 和 diff 检查均通过。
This commit is contained in:
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
func publicGatewayTask(task store.GatewayTask) store.GatewayTask {
|
||||
if task.Status == "failed" || task.Status == "cancelled" || task.ErrorCode != "" || task.ErrorMessage != "" {
|
||||
value := publicerror.FromFields(task.ErrorCode, firstNonEmpty(task.ErrorMessage, task.Error), storedTaskErrorStatus(task.ErrorCode), false)
|
||||
if task.PublicError != nil && task.PublicError.Code != "" {
|
||||
value := publicerror.FromFields(task.ErrorCode, firstNonEmpty(task.ErrorMessage, task.Error), taskErrorHTTPStatus(task), false)
|
||||
if task.PublicError != nil && task.PublicError.Code != "" && task.PublicError.Source != "" {
|
||||
value = *task.PublicError
|
||||
}
|
||||
value = publicerror.WithIDs(value, task.RequestID, task.ID)
|
||||
@@ -21,6 +21,7 @@ func publicGatewayTask(task store.GatewayTask) store.GatewayTask {
|
||||
task.ErrorMessage = value.Message
|
||||
task.Error = value.Message
|
||||
}
|
||||
task.Attempts = append([]store.TaskAttempt(nil), task.Attempts...)
|
||||
for index := range task.Attempts {
|
||||
attempt := &task.Attempts[index]
|
||||
if attempt.ErrorCode == "" && attempt.ErrorMessage == "" {
|
||||
@@ -31,7 +32,7 @@ func publicGatewayTask(task store.GatewayTask) store.GatewayTask {
|
||||
status = http.StatusBadGateway
|
||||
}
|
||||
value := publicerror.FromFields(attempt.ErrorCode, attempt.ErrorMessage, status, attempt.Retryable)
|
||||
if attempt.PublicError != nil && attempt.PublicError.Code != "" {
|
||||
if attempt.PublicError != nil && attempt.PublicError.Code != "" && attempt.PublicError.Source != "" {
|
||||
value = *attempt.PublicError
|
||||
}
|
||||
value = publicerror.WithIDs(value, attempt.RequestID, task.ID)
|
||||
@@ -43,16 +44,48 @@ func publicGatewayTask(task store.GatewayTask) store.GatewayTask {
|
||||
}
|
||||
|
||||
func publicTaskError(task store.GatewayTask) publicerror.Error {
|
||||
if task.PublicError != nil && task.PublicError.Code != "" {
|
||||
if task.PublicError != nil && task.PublicError.Code != "" && task.PublicError.Source != "" {
|
||||
return publicerror.WithIDs(*task.PublicError, task.RequestID, task.ID)
|
||||
}
|
||||
status := storedTaskErrorStatus(task.ErrorCode)
|
||||
status := taskErrorHTTPStatus(task)
|
||||
if status <= 0 {
|
||||
status = http.StatusBadGateway
|
||||
}
|
||||
return publicerror.WithIDs(publicerror.FromFields(task.ErrorCode, firstNonEmpty(task.ErrorMessage, task.Error, task.Message), status, false), task.RequestID, task.ID)
|
||||
}
|
||||
|
||||
func taskErrorHTTPStatus(task store.GatewayTask) int {
|
||||
if task.PublicError != nil && task.PublicError.Source != "" && task.PublicError.HTTPStatus >= 400 {
|
||||
return task.PublicError.HTTPStatus
|
||||
}
|
||||
for index := len(task.Attempts) - 1; index >= 0; index-- {
|
||||
if status := task.Attempts[index].StatusCode; status >= 400 && status <= 599 {
|
||||
return status
|
||||
}
|
||||
}
|
||||
if status := publicErrorInt(task.Metrics["statusCode"]); status >= 400 && status <= 599 {
|
||||
return status
|
||||
}
|
||||
return storedTaskErrorStatus(task.ErrorCode)
|
||||
}
|
||||
|
||||
func publicErrorInt(value any) int {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
return typed
|
||||
case int32:
|
||||
return int(typed)
|
||||
case int64:
|
||||
return int(typed)
|
||||
case float32:
|
||||
return int(typed)
|
||||
case float64:
|
||||
return int(typed)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func publicTaskList(items []store.GatewayTask) []store.GatewayTask {
|
||||
out := make([]store.GatewayTask, len(items))
|
||||
for index, task := range items {
|
||||
@@ -63,7 +96,7 @@ func publicTaskList(items []store.GatewayTask) []store.GatewayTask {
|
||||
|
||||
func publicErrorMap(value publicerror.Error) map[string]any {
|
||||
out := map[string]any{
|
||||
"code": value.Code, "message": value.Message, "category": value.Category,
|
||||
"code": value.Code, "message": value.Message, "category": value.Category, "source": value.Source,
|
||||
"httpStatus": value.HTTPStatus, "retryable": value.Retryable, "action": value.Action,
|
||||
"version": value.Version,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user