fix(upstream): passthrough response body directly instead of parsing SSE
ForwardUpstream/ForwardUpstreamGemini should pipe the upstream response directly to the client (headers + body), not parse it as SSE stream.
This commit is contained in:
@@ -3530,39 +3530,30 @@ func (s *AntigravityGatewayService) ForwardUpstream(ctx context.Context, c *gin.
|
|||||||
return nil, s.writeMappedClaudeError(c, account, resp.StatusCode, resp.Header.Get("x-request-id"), respBody)
|
return nil, s.writeMappedClaudeError(c, account, resp.StatusCode, resp.Header.Get("x-request-id"), respBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 成功响应
|
// 成功响应:透传 response header + body
|
||||||
requestID := resp.Header.Get("x-request-id")
|
requestID := resp.Header.Get("x-request-id")
|
||||||
if requestID != "" {
|
|
||||||
c.Header("x-request-id", requestID)
|
// 透传上游响应头(排除 hop-by-hop)
|
||||||
|
for key, values := range resp.Header {
|
||||||
|
if upstreamHopByHopHeaders[strings.ToLower(key)] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, v := range values {
|
||||||
|
c.Header(key, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var usage *ClaudeUsage
|
c.Status(resp.StatusCode)
|
||||||
var firstTokenMs *int
|
_, copyErr := io.Copy(c.Writer, resp.Body)
|
||||||
if claudeReq.Stream {
|
if copyErr != nil {
|
||||||
streamRes, err := s.handleClaudeStreamingResponse(c, resp, startTime, originalModel)
|
log.Printf("%s status=copy_error error=%v", prefix, copyErr)
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s status=stream_error error=%v", prefix, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
usage = streamRes.usage
|
|
||||||
firstTokenMs = streamRes.firstTokenMs
|
|
||||||
} else {
|
|
||||||
streamRes, err := s.handleClaudeStreamToNonStreaming(c, resp, startTime, originalModel)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s status=stream_collect_error error=%v", prefix, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
usage = streamRes.usage
|
|
||||||
firstTokenMs = streamRes.firstTokenMs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ForwardResult{
|
return &ForwardResult{
|
||||||
RequestID: requestID,
|
RequestID: requestID,
|
||||||
Usage: *usage,
|
Model: originalModel,
|
||||||
Model: originalModel,
|
Stream: claudeReq.Stream,
|
||||||
Stream: claudeReq.Stream,
|
Duration: time.Since(startTime),
|
||||||
Duration: time.Since(startTime),
|
|
||||||
FirstTokenMs: firstTokenMs,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3712,35 +3703,23 @@ func (s *AntigravityGatewayService) ForwardUpstreamGemini(ctx context.Context, c
|
|||||||
return nil, fmt.Errorf("antigravity upstream error: %d", resp.StatusCode)
|
return nil, fmt.Errorf("antigravity upstream error: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 成功响应
|
// 成功响应:透传 response header + body
|
||||||
requestID := resp.Header.Get("x-request-id")
|
requestID := resp.Header.Get("x-request-id")
|
||||||
if requestID != "" {
|
|
||||||
c.Header("x-request-id", requestID)
|
// 透传上游响应头(排除 hop-by-hop)
|
||||||
|
for key, values := range resp.Header {
|
||||||
|
if upstreamHopByHopHeaders[strings.ToLower(key)] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, v := range values {
|
||||||
|
c.Header(key, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var usage *ClaudeUsage
|
c.Status(resp.StatusCode)
|
||||||
var firstTokenMs *int
|
_, copyErr := io.Copy(c.Writer, resp.Body)
|
||||||
|
if copyErr != nil {
|
||||||
if stream {
|
log.Printf("%s status=copy_error error=%v", prefix, copyErr)
|
||||||
streamRes, err := s.handleGeminiStreamingResponse(c, resp, startTime)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s status=stream_error error=%v", prefix, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
usage = streamRes.usage
|
|
||||||
firstTokenMs = streamRes.firstTokenMs
|
|
||||||
} else {
|
|
||||||
streamRes, err := s.handleGeminiStreamToNonStreaming(c, resp, startTime)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s status=stream_collect_error error=%v", prefix, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
usage = streamRes.usage
|
|
||||||
firstTokenMs = streamRes.firstTokenMs
|
|
||||||
}
|
|
||||||
|
|
||||||
if usage == nil {
|
|
||||||
usage = &ClaudeUsage{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
imageCount := 0
|
imageCount := 0
|
||||||
@@ -3749,13 +3728,11 @@ func (s *AntigravityGatewayService) ForwardUpstreamGemini(ctx context.Context, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &ForwardResult{
|
return &ForwardResult{
|
||||||
RequestID: requestID,
|
RequestID: requestID,
|
||||||
Usage: *usage,
|
Model: originalModel,
|
||||||
Model: originalModel,
|
Stream: stream,
|
||||||
Stream: stream,
|
Duration: time.Since(startTime),
|
||||||
Duration: time.Since(startTime),
|
ImageCount: imageCount,
|
||||||
FirstTokenMs: firstTokenMs,
|
ImageSize: imageSize,
|
||||||
ImageCount: imageCount,
|
|
||||||
ImageSize: imageSize,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user