feat: track upstream request ID and prevent response header override

When proxying through another new-api instance, the upstream
X-Oneapi-Request-Id was overwriting the local one in client responses.
This adds a new `upstream_request_id` field to the logs table, captures
the upstream ID during relay, and filters it from being copied back to
the client. Frontend gains search/filter and detail display support.
This commit is contained in:
CaIon
2026-05-12 21:53:37 +08:00
parent 428e3d91f2
commit aa56667b8f
20 changed files with 112 additions and 32 deletions
+20 -2
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net/http"
"strings"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/logger"
@@ -22,6 +23,24 @@ func CloseResponseBodyGracefully(httpResponse *http.Response) {
}
}
// ShouldCopyUpstreamHeader checks whether a given upstream response header
// should be copied to the client response. It returns false for Content-Length
// (managed separately) and X-Oneapi-Request-Id (to preserve the local instance
// ID). When the upstream header is X-Oneapi-Request-Id, the value is captured
// into the Gin context for later logging.
func ShouldCopyUpstreamHeader(c *gin.Context, k string, v []string) bool {
if strings.EqualFold(k, "Content-Length") {
return false
}
if strings.EqualFold(k, common.RequestIdKey) {
if c != nil && len(v) > 0 {
c.Set(common.UpstreamRequestIdKey, v[0])
}
return false
}
return true
}
func IOCopyBytesGracefully(c *gin.Context, src *http.Response, data []byte) {
if c.Writer == nil {
return
@@ -35,8 +54,7 @@ func IOCopyBytesGracefully(c *gin.Context, src *http.Response, data []byte) {
// For example, Postman will report error, and we cannot check the response at all.
if src != nil {
for k, v := range src.Header {
// avoid setting Content-Length
if k == "Content-Length" {
if !ShouldCopyUpstreamHeader(c, k, v) {
continue
}
c.Writer.Header().Set(k, v[0])