Files
ttstd-infinite-canvas/backend/internal/app/provider_error_message.go

56 lines
2.0 KiB
Go

package app
import (
"encoding/json"
"regexp"
"strings"
)
var providerErrorURL = regexp.MustCompile(`(?i)https?://[^\s<>"',。;)]+`)
var providerErrorSensitive = regexp.MustCompile(`(?i)余额|额度|配额|欠费|账单|充值|计费|密钥|密码|令牌|balance|quota|billing|credit|payment|funds|wallet|api[ _-]?key|authorization|bearer|cookie|(?:access|refresh|auth|session)[ _-]?token|token\s*[=:]|secret|password|credential|sk-[a-z0-9]|tenant|trace[ _-]?id|request[ _-]?id|internal stack|stack\s*trace|dial tcp|no such host|prompt\s*[=:]`)
// 只提取错误消息字段,不序列化整个响应,避免回传 headers、请求正文和诊断信息。
func providerErrorDetail(raw string) string {
raw = strings.TrimSpace(raw)
var payload any
if json.Unmarshal([]byte(raw), &payload) == nil {
raw = providerErrorMessageField(payload)
} else if strings.HasPrefix(raw, "{") || strings.HasPrefix(raw, "[") {
return ""
}
// 网关 HTML、敏感账务/凭据诊断整条隐藏;普通消息里的 URL 单独移除。
if strings.HasPrefix(raw, "{") || strings.HasPrefix(raw, "[") || strings.ContainsAny(raw, "<>") || providerErrorSensitive.MatchString(raw) {
return ""
}
raw = providerErrorURL.ReplaceAllString(raw, "[链接已隐藏]")
return truncateRunes(strings.Join(strings.Fields(raw), " "), 1_500)
}
func providerErrorMessageField(value any) string {
switch value := value.(type) {
case string:
return strings.TrimSpace(value)
case map[string]any:
for _, key := range []string{"error", "message", "msg", "detail"} {
if message := providerErrorMessageField(value[key]); message != "" {
return message
}
}
}
return ""
}
func providerErrorWithDetail(fallback, raw string) string {
if message, ok := providerPayloadErrorCategory(raw); ok {
fallback = message
}
return appendProviderErrorDetail(fallback, raw)
}
func appendProviderErrorDetail(fallback, raw string) string {
if detail := providerErrorDetail(raw); detail != "" && detail != fallback {
return fallback + ";上游:" + detail
}
return fallback
}