110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"chat-agent-system/internal/errcode"
|
|
"chat-agent-system/internal/httpx"
|
|
)
|
|
|
|
func writeJSONResponse(w http.ResponseWriter, status int, data any) {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(status)
|
|
_ = json.NewEncoder(w).Encode(data)
|
|
}
|
|
|
|
func writeSafeError(w http.ResponseWriter, r *http.Request, status int, legacy string) {
|
|
emitError(w, r, status, errcode.FromLegacy(status, legacy), legacy)
|
|
}
|
|
|
|
func writeDomainError(w http.ResponseWriter, r *http.Request, status int, err error) {
|
|
if err == nil {
|
|
writeSafeError(w, r, status, "")
|
|
return
|
|
}
|
|
if st, ok := domainHTTPStatus(err); ok {
|
|
def := errcode.FromStatus(st)
|
|
if d, found := errcode.FromError(err); found {
|
|
def = d
|
|
}
|
|
emitError(w, r, st, def, err.Error())
|
|
return
|
|
}
|
|
if def, found := errcode.FromError(err); found {
|
|
// 处理器传入的状态是既有 HTTP 契约。注册表状态只在调用方未给出时使用。
|
|
st := status
|
|
if st == 0 {
|
|
st = def.Status
|
|
}
|
|
if st == 0 {
|
|
st = http.StatusInternalServerError
|
|
}
|
|
emitError(w, r, st, def, err.Error())
|
|
return
|
|
}
|
|
emitError(w, r, status, errcode.FromLegacy(status, err.Error()), err.Error())
|
|
}
|
|
|
|
func emitError(w http.ResponseWriter, r *http.Request, status int, def errcode.Def, legacy string) {
|
|
if def.ID == "" {
|
|
def = errcode.FromStatus(status)
|
|
}
|
|
details := map[string]any{}
|
|
if def.Guide != "" {
|
|
details["guide"] = def.Guide
|
|
}
|
|
if def.Module != "" {
|
|
details["module"] = def.Module
|
|
}
|
|
rid := incomingRequestID(w, r)
|
|
httpx.WriteHTTP(w, r, status, def.ID, legacy, rid, def.Message, details)
|
|
if rid == "" && w != nil {
|
|
rid = w.Header().Get(httpx.HeaderRequestID)
|
|
}
|
|
reportHTTPError(r, status, def, rid, legacy)
|
|
}
|
|
|
|
func incomingRequestID(w http.ResponseWriter, r *http.Request) string {
|
|
if r != nil {
|
|
if v := strings.TrimSpace(r.Header.Get(httpx.HeaderRequestID)); v != "" {
|
|
return v
|
|
}
|
|
}
|
|
if w != nil {
|
|
if v := strings.TrimSpace(w.Header().Get(httpx.HeaderRequestID)); v != "" {
|
|
return v
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func reportHTTPError(r *http.Request, status int, def errcode.Def, requestID, legacy string) {
|
|
ev := errcode.Event{
|
|
Code: def.ID,
|
|
Class: def.Class,
|
|
HTTPStatus: status,
|
|
RequestID: requestID,
|
|
Module: def.Module,
|
|
Source: "http",
|
|
Retryable: def.Retryable,
|
|
UserMessage: def.Message,
|
|
Upstream: legacy,
|
|
}
|
|
ctx := context.Background()
|
|
if r != nil {
|
|
ev.Method = r.Method
|
|
ev.Path = r.URL.Path
|
|
if sid := strings.TrimSpace(r.URL.Query().Get("session_id")); sid != "" {
|
|
ev.SessionID = sid
|
|
}
|
|
if user := principalFromContext(r.Context()); user != nil {
|
|
ev.ActorUserID = user.ID
|
|
}
|
|
ctx = r.Context()
|
|
}
|
|
errcode.Report(ctx, ev)
|
|
}
|