Skip to content

Commit a8f5068

Browse files
committed
refactor(handlers): 统一多提供商原生处理器的错误响应格式
将 Anthropic 和 Gemini 处理器的错误响应从 fiber.Map 改为类型化的错误结构体: - Anthropic: 使用 anthropicTypes.ErrorResponse 替代 fiber.Map - Gemini: 使用 geminiTypes.ErrorResponse 替代 fiber.Map,并更新 Swagger 文档 - OpenAI: 新增 sendOpenAIResponsesStreamError 函数处理 Responses API 流式错误 改进点: - 统一错误响应格式,符合各提供商 API 规范 - 增强类型安全性,避免运行时错误 - 完善 Swagger 文档的错误响应类型定义
1 parent c03e696 commit a8f5068

File tree

3 files changed

+67
-21
lines changed

3 files changed

+67
-21
lines changed

handlers/multi/native/handler_anthropic.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ import (
3232
func (h *Handler) AnthropicMessages(c *fiber.Ctx) error {
3333
var req anthropicTypes.Request
3434
if err := c.BodyParser(&req); err != nil {
35-
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
36-
"error": fmt.Sprintf("无效的请求体: %v", err),
35+
return c.Status(fiber.StatusBadRequest).JSON(anthropicTypes.ErrorResponse{
36+
Type: "error",
37+
Error: anthropicTypes.Error{
38+
Type: "invalid_request_error",
39+
Message: fmt.Sprintf("无效的请求体: %v", err),
40+
},
3741
})
3842
}
3943

@@ -49,8 +53,12 @@ func (h *Handler) AnthropicMessages(c *fiber.Ctx) error {
4953

5054
resp, err := h.portalService.NativeAnthropicMessages(c.Context(), &req)
5155
if err != nil {
52-
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
53-
"error": fmt.Sprintf("请求失败: %v", err),
56+
return c.Status(fiber.StatusInternalServerError).JSON(anthropicTypes.ErrorResponse{
57+
Type: "error",
58+
Error: anthropicTypes.Error{
59+
Type: "api_error",
60+
Message: fmt.Sprintf("请求失败: %v", err),
61+
},
5462
})
5563
}
5664

handlers/multi/native/handler_gemini.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ import (
2626
// @Param model path string true "模型名称"
2727
// @Param request body geminiTypes.Request true "请求体"
2828
// @Success 200 {object} geminiTypes.Response "成功"
29-
// @Failure 400 {object} map[string]string "无效的请求体或缺少模型参数"
30-
// @Failure 500 {object} map[string]string "请求失败"
29+
// @Failure 400 {object} geminiTypes.ErrorResponse "无效的请求体或缺少模型参数"
30+
// @Failure 500 {object} geminiTypes.ErrorResponse "请求失败"
3131
// @Router /multi/native/v1beta/models/{model}:generateContent [post]
3232
// @Security ApiKeyAuth
3333
func (h *Handler) GeminiGenerateContent(c *fiber.Ctx) error {
3434
var req geminiTypes.Request
3535
if err := c.BodyParser(&req); err != nil {
36-
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
37-
"error": fmt.Sprintf("无效的请求体: %v", err),
36+
return c.Status(fiber.StatusBadRequest).JSON(geminiTypes.ErrorResponse{
37+
Error: geminiTypes.ErrorDetail{
38+
Code: fiber.StatusBadRequest,
39+
Message: fmt.Sprintf("无效的请求体: %v", err),
40+
Status: "INVALID_ARGUMENT",
41+
},
3842
})
3943
}
4044

@@ -51,15 +55,23 @@ func (h *Handler) GeminiGenerateContent(c *fiber.Ctx) error {
5155
req.Model = strings.TrimSpace(c.Query("model"))
5256
}
5357
if req.Model == "" {
54-
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
55-
"error": "缺少模型查询参数",
58+
return c.Status(fiber.StatusBadRequest).JSON(geminiTypes.ErrorResponse{
59+
Error: geminiTypes.ErrorDetail{
60+
Code: fiber.StatusBadRequest,
61+
Message: "缺少模型查询参数",
62+
Status: "INVALID_ARGUMENT",
63+
},
5664
})
5765
}
5866

5967
resp, err := h.portalService.NativeGeminiGenerateContent(c.Context(), &req)
6068
if err != nil {
61-
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
62-
"error": fmt.Sprintf("请求失败: %v", err),
69+
return c.Status(fiber.StatusInternalServerError).JSON(geminiTypes.ErrorResponse{
70+
Error: geminiTypes.ErrorDetail{
71+
Code: fiber.StatusInternalServerError,
72+
Message: fmt.Sprintf("请求失败: %v", err),
73+
Status: "INTERNAL",
74+
},
6375
})
6476
}
6577

@@ -78,14 +90,18 @@ func (h *Handler) GeminiGenerateContent(c *fiber.Ctx) error {
7890
// @Param model path string true "模型名称"
7991
// @Param request body geminiTypes.Request true "请求体"
8092
// @Success 200 {string} string "流式事件数据"
81-
// @Failure 400 {object} map[string]string "无效的请求体或缺少模型参数"
93+
// @Failure 400 {object} geminiTypes.ErrorResponse "无效的请求体或缺少模型参数"
8294
// @Router /multi/native/v1beta/models/{model}:streamGenerateContent [post]
8395
// @Security ApiKeyAuth
8496
func (h *Handler) GeminiStreamGenerateContent(c *fiber.Ctx) error {
8597
var req geminiTypes.Request
8698
if err := c.BodyParser(&req); err != nil {
87-
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
88-
"error": fmt.Sprintf("无效的请求体: %v", err),
99+
return c.Status(fiber.StatusBadRequest).JSON(geminiTypes.ErrorResponse{
100+
Error: geminiTypes.ErrorDetail{
101+
Code: fiber.StatusBadRequest,
102+
Message: fmt.Sprintf("无效的请求体: %v", err),
103+
Status: "INVALID_ARGUMENT",
104+
},
89105
})
90106
}
91107

@@ -102,8 +118,12 @@ func (h *Handler) GeminiStreamGenerateContent(c *fiber.Ctx) error {
102118
req.Model = strings.TrimSpace(c.Query("model"))
103119
}
104120
if req.Model == "" {
105-
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
106-
"error": "缺少模型查询参数",
121+
return c.Status(fiber.StatusBadRequest).JSON(geminiTypes.ErrorResponse{
122+
Error: geminiTypes.ErrorDetail{
123+
Code: fiber.StatusBadRequest,
124+
Message: "缺少模型查询参数",
125+
Status: "INVALID_ARGUMENT",
126+
},
107127
})
108128
}
109129

handlers/multi/native/handler_openai.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,24 @@ func (h *Handler) streamOpenAIChat(c *fiber.Ctx, req *openaiChatTypes.Request, s
173173
return nil
174174
}
175175

176+
// sendOpenAIResponsesStreamError 发送 OpenAI Responses 流式错误事件。
177+
func (h *Handler) sendOpenAIResponsesStreamError(w *bufio.Writer, code, message, param string) {
178+
codePtr := &code
179+
paramPtr := &param
180+
181+
errEvent := openaiResponsesTypes.ResponseErrorEvent{
182+
Type: openaiResponsesTypes.StreamEventError,
183+
Code: codePtr,
184+
Message: message,
185+
Param: paramPtr,
186+
SequenceNumber: 0,
187+
}
188+
189+
data, _ := json.Marshal(errEvent)
190+
fmt.Fprintf(w, "data: %s\n\n", data)
191+
w.Flush()
192+
}
193+
176194
// sendOpenAIStreamError 发送流式错误响应
177195
func (h *Handler) sendOpenAIStreamError(w *bufio.Writer, errorType, message, code string) {
178196
errResp := openaiSharedTypes.Error{
@@ -205,7 +223,7 @@ func (h *Handler) streamOpenAIResponses(c *fiber.Ctx, req *openaiResponsesTypes.
205223
stack := debug.Stack()
206224
stackLines := strings.Split(strings.TrimSpace(string(stack)), "\n")
207225
logger.Error("原生流处理异常", "panic", r, "stack", stackLines)
208-
h.sendOpenAIStreamError(w, "internal_error", fmt.Sprintf("异常: %v", r), "internal_error")
226+
h.sendOpenAIResponsesStreamError(w, "internal_error", fmt.Sprintf("异常: %v", r), "internal_error")
209227
}
210228
}()
211229

@@ -214,14 +232,14 @@ func (h *Handler) streamOpenAIResponses(c *fiber.Ctx, req *openaiResponsesTypes.
214232
if err != nil {
215233
cancel()
216234
logger.Error("序列化流事件失败", "error", err)
217-
h.sendOpenAIStreamError(w, "internal_error", fmt.Sprintf("序列化流事件失败: %v", err), "internal_error")
235+
h.sendOpenAIResponsesStreamError(w, "internal_error", fmt.Sprintf("序列化流事件失败: %v", err), "internal_error")
218236
break
219237
}
220238

221239
if _, err := fmt.Fprintf(w, "data: %s\n\n", data); err != nil {
222240
cancel()
223241
logger.Error("写入流事件失败", "error", err)
224-
h.sendOpenAIStreamError(w, "internal_error", fmt.Sprintf("写入流事件失败: %v", err), "internal_error")
242+
h.sendOpenAIResponsesStreamError(w, "internal_error", fmt.Sprintf("写入流事件失败: %v", err), "internal_error")
225243
break
226244
}
227245

@@ -233,7 +251,7 @@ func (h *Handler) streamOpenAIResponses(c *fiber.Ctx, req *openaiResponsesTypes.
233251
if _, err := fmt.Fprintf(w, "data: [DONE]\n\n"); err != nil {
234252
cancel()
235253
logger.Error("写入流结束标识失败", "error", err)
236-
h.sendOpenAIStreamError(w, "internal_error", fmt.Sprintf("写入流结束标识失败: %v", err), "internal_error")
254+
h.sendOpenAIResponsesStreamError(w, "internal_error", fmt.Sprintf("写入流结束标识失败: %v", err), "internal_error")
237255
}
238256
w.Flush()
239257
}

0 commit comments

Comments
 (0)