**fix(handlers): refactor API response capture to append data safely**

- Introduced `appendAPIResponse` helper to preserve and append data to existing API responses.
- Ensured newline inclusion when appending, if necessary.
- Improved `nil` and data type checks for response handling.
- Updated middleware to skip request logging for `GET` requests.
This commit is contained in:
Luis Pater
2025-11-25 11:37:02 +08:00
parent 113db3c5bf
commit 506f1117dd
2 changed files with 33 additions and 4 deletions

View File

@@ -6,6 +6,7 @@ package middleware
import ( import (
"bytes" "bytes"
"io" "io"
"net/http"
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -24,6 +25,11 @@ func RequestLoggingMiddleware(logger logging.RequestLogger) gin.HandlerFunc {
return return
} }
if c.Request.Method == http.MethodGet {
c.Next()
return
}
path := c.Request.URL.Path path := c.Request.URL.Path
if !shouldLogRequest(path) { if !shouldLogRequest(path) {
c.Next() c.Next()

View File

@@ -4,6 +4,7 @@
package handlers package handlers
import ( import (
"bytes"
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
@@ -120,11 +121,11 @@ func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *
data := params[0] data := params[0]
switch data.(type) { switch data.(type) {
case []byte: case []byte:
c.Set("API_RESPONSE", data.([]byte)) appendAPIResponse(c, data.([]byte))
case error: case error:
c.Set("API_RESPONSE", []byte(data.(error).Error())) appendAPIResponse(c, []byte(data.(error).Error()))
case string: case string:
c.Set("API_RESPONSE", []byte(data.(string))) appendAPIResponse(c, []byte(data.(string)))
case bool: case bool:
case nil: case nil:
} }
@@ -135,6 +136,28 @@ func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *
} }
} }
// appendAPIResponse preserves any previously captured API response and appends new data.
func appendAPIResponse(c *gin.Context, data []byte) {
if c == nil || len(data) == 0 {
return
}
if existing, exists := c.Get("API_RESPONSE"); exists {
if existingBytes, ok := existing.([]byte); ok && len(existingBytes) > 0 {
combined := make([]byte, 0, len(existingBytes)+len(data)+1)
combined = append(combined, existingBytes...)
if existingBytes[len(existingBytes)-1] != '\n' {
combined = append(combined, '\n')
}
combined = append(combined, data...)
c.Set("API_RESPONSE", combined)
return
}
}
c.Set("API_RESPONSE", bytes.Clone(data))
}
// ExecuteWithAuthManager executes a non-streaming request via the core auth manager. // ExecuteWithAuthManager executes a non-streaming request via the core auth manager.
// This path is the only supported execution route. // This path is the only supported execution route.
func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, *interfaces.ErrorMessage) { func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, *interfaces.ErrorMessage) {
@@ -297,7 +320,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
func (h *BaseAPIHandler) getRequestDetails(modelName string) (providers []string, normalizedModel string, metadata map[string]any, err *interfaces.ErrorMessage) { func (h *BaseAPIHandler) getRequestDetails(modelName string) (providers []string, normalizedModel string, metadata map[string]any, err *interfaces.ErrorMessage) {
// Resolve "auto" model to an actual available model first // Resolve "auto" model to an actual available model first
resolvedModelName := util.ResolveAutoModel(modelName) resolvedModelName := util.ResolveAutoModel(modelName)
providerName, extractedModelName, isDynamic := h.parseDynamicModel(resolvedModelName) providerName, extractedModelName, isDynamic := h.parseDynamicModel(resolvedModelName)
// First, normalize the model name to handle suffixes like "-thinking-128" // First, normalize the model name to handle suffixes like "-thinking-128"