refactor(gateway): introduce OpenAI request view

Cache hot-path request scalars before full body decoding so later branches can avoid repeated map work while preserving current decode behavior.
This commit is contained in:
name
2026-05-31 01:01:58 +08:00
parent 34de99ee0e
commit 6a5f6b96b6
2 changed files with 55 additions and 10 deletions
@@ -2346,7 +2346,8 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco
}
originalBody := body
reqModel, reqStream, promptCacheKey := extractOpenAIRequestMetaFromBody(body)
requestView := newOpenAIRequestView(body)
reqModel, reqStream, promptCacheKey := requestView.Model, requestView.Stream, requestView.PromptCacheKey
originalModel := reqModel
if account.Type == AccountTypeAPIKey && !openai_compat.ShouldUseResponsesAPI(account.Extra) {
@@ -2396,7 +2397,7 @@ func (s *OpenAIGatewayService) Forward(ctx context.Context, c *gin.Context, acco
return s.forwardOpenAIPassthrough(ctx, c, account, originalBody, reqModel, reasoningEffort, reqStream, startTime)
}
reqBody, err := getOpenAIRequestBodyMap(c, body)
reqBody, err := requestView.Decode(c)
if err != nil {
return nil, err
}
@@ -6274,15 +6275,39 @@ func deriveOpenAIReasoningEffortFromModel(model string) string {
return normalizeOpenAIReasoningEffort(parts[len(parts)-1])
}
func extractOpenAIRequestMetaFromBody(body []byte) (model string, stream bool, promptCacheKey string) {
if len(body) == 0 {
return "", false, ""
}
type openAIRequestView struct {
body []byte
Model string
Stream bool
PromptCacheKey string
PreviousResponseID string
ServiceTier string
ReasoningEffort string
}
model = strings.TrimSpace(gjson.GetBytes(body, "model").String())
stream = gjson.GetBytes(body, "stream").Bool()
promptCacheKey = strings.TrimSpace(gjson.GetBytes(body, "prompt_cache_key").String())
return model, stream, promptCacheKey
func newOpenAIRequestView(body []byte) openAIRequestView {
if len(body) == 0 {
return openAIRequestView{}
}
return openAIRequestView{
body: body,
Model: strings.TrimSpace(gjson.GetBytes(body, "model").String()),
Stream: gjson.GetBytes(body, "stream").Bool(),
PromptCacheKey: strings.TrimSpace(gjson.GetBytes(body, "prompt_cache_key").String()),
PreviousResponseID: strings.TrimSpace(gjson.GetBytes(body, "previous_response_id").String()),
ServiceTier: strings.TrimSpace(gjson.GetBytes(body, "service_tier").String()),
ReasoningEffort: strings.TrimSpace(gjson.GetBytes(body, "reasoning.effort").String()),
}
}
// Decode 保留阶段一既有 full-map 行为;后续阶段会把调用点下沉到复杂分支。
func (v openAIRequestView) Decode(c *gin.Context) (map[string]any, error) {
return getOpenAIRequestBodyMap(c, v.body)
}
func extractOpenAIRequestMetaFromBody(body []byte) (model string, stream bool, promptCacheKey string) {
view := newOpenAIRequestView(body)
return view.Model, view.Stream, view.PromptCacheKey
}
// normalizeOpenAIPassthroughOAuthBody 将透传 OAuth 请求体收敛为旧链路关键行为:
@@ -9,6 +9,26 @@ import (
"github.com/stretchr/testify/require"
)
func TestOpenAIRequestView_ExtractsRawScalars(t *testing.T) {
view := newOpenAIRequestView([]byte(`{"model":" gpt-5 ","stream":true,"prompt_cache_key":" ses-1 ","previous_response_id":" resp-1 ","service_tier":" fast ","reasoning":{"effort":" medium "}}`))
require.Equal(t, "gpt-5", view.Model)
require.True(t, view.Stream)
require.Equal(t, "ses-1", view.PromptCacheKey)
require.Equal(t, "resp-1", view.PreviousResponseID)
require.Equal(t, "fast", view.ServiceTier)
require.Equal(t, "medium", view.ReasoningEffort)
}
func TestOpenAIRequestView_DecodeKeepsFullMapBehavior(t *testing.T) {
view := newOpenAIRequestView([]byte(`{"model":"gpt-5","stream":true,"input":[{"type":"message","content":"hi"}]}`))
reqBody, err := view.Decode(nil)
require.NoError(t, err)
require.Equal(t, "gpt-5", reqBody["model"])
require.IsType(t, []any{}, reqBody["input"])
}
func TestExtractOpenAIRequestMetaFromBody(t *testing.T) {
tests := []struct {
name string