fix(openai): 修复 OAuth 透传流式断开与压缩头问题
- 透传流式在客户端断开后继续 drain 上游并解析 usage,避免计费信息丢失 - 阻断透传 accept-encoding,避免压缩响应影响 SSE/usage 解析 - 阻断 proxy-authorization,避免透传代理鉴权信息 - 补充回归测试:请求头阻断与断流后 usage 采集
This commit is contained in:
@@ -1183,7 +1183,10 @@ func isOpenAIPassthroughBlockedRequestHeader(lowerKey string) bool {
|
||||
case "connection", "transfer-encoding", "keep-alive", "proxy-connection", "upgrade", "te", "trailer":
|
||||
return true
|
||||
// 入站鉴权与潜在泄露
|
||||
case "authorization", "x-api-key", "x-goog-api-key", "cookie":
|
||||
case "authorization", "x-api-key", "x-goog-api-key", "cookie", "proxy-authorization":
|
||||
return true
|
||||
// 由 Go http client 自动协商压缩;透传模式需避免上游返回压缩体影响 SSE/usage 解析
|
||||
case "accept-encoding":
|
||||
return true
|
||||
// 由 HTTP 库管理
|
||||
case "host", "content-length":
|
||||
@@ -1224,6 +1227,7 @@ func (s *OpenAIGatewayService) handleStreamingResponsePassthrough(
|
||||
|
||||
usage := &OpenAIUsage{}
|
||||
var firstTokenMs *int
|
||||
clientDisconnected := false
|
||||
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
maxLineSize := defaultMaxLineSize
|
||||
@@ -1245,13 +1249,20 @@ func (s *OpenAIGatewayService) handleStreamingResponsePassthrough(
|
||||
s.parseSSEUsage(data, usage)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintln(w, line); err != nil {
|
||||
// 客户端断开时停止写入
|
||||
break
|
||||
if !clientDisconnected {
|
||||
if _, err := fmt.Fprintln(w, line); err != nil {
|
||||
clientDisconnected = true
|
||||
log.Printf("[OpenAI passthrough] Client disconnected during streaming, continue draining upstream for usage: account=%d", account.ID)
|
||||
} else {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
flusher.Flush()
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
if clientDisconnected {
|
||||
log.Printf("[OpenAI passthrough] Upstream read error after client disconnect: account=%d err=%v", account.ID, err)
|
||||
return &openaiStreamingResultPassthrough{usage: usage, firstTokenMs: firstTokenMs}, nil
|
||||
}
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return &openaiStreamingResultPassthrough{usage: usage, firstTokenMs: firstTokenMs}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user