diff --git a/.env.example b/.env.example index 001d128..c7c12eb 100644 --- a/.env.example +++ b/.env.example @@ -27,7 +27,7 @@ OT_MASTER_KEY=change-me-master-key OT_PROXY_UPSTREAM_KEY= OT_PROXY_UPSTREAM_BASE_URL=https://api.openai.com OT_PROXY_DEFAULT_MODEL=gpt-4o-mini -OT_PROXY_TIMEOUT=120s +OT_PROXY_TIMEOUT=300s # 渠道健康检查 OT_PROXY_HEALTH_INTERVAL=60s @@ -50,4 +50,4 @@ OT_ADMIN_EMAIL=admin@localhost OT_ADMIN_PASSWORD=admin123 # 记录原始请求日志 -OT_PROXY_LOG_RAW=false \ No newline at end of file +OT_PROXY_LOG_RAW=false diff --git a/server/internal/cli/serve.go b/server/internal/cli/serve.go index d8ac56a..7ac6b91 100644 --- a/server/internal/cli/serve.go +++ b/server/internal/cli/serve.go @@ -31,7 +31,7 @@ func serve() error { } defer a.Shutdown(context.Background()) - gw := proxy.NewGateway(a.DB, a.Enc, a.Usage, a.Limit, cfg.RateLimit.UserRPS, cfg.Proxy.LogRaw) + gw := proxy.NewGateway(a.DB, a.Enc, a.Usage, a.Limit, cfg.RateLimit.UserRPS, cfg.Proxy.LogRaw, cfg.Proxy.Timeout) router := api.NewRouter(a, gw) srv := &http.Server{ @@ -59,4 +59,4 @@ func serve() error { } a.Usage.Close() return nil -} \ No newline at end of file +} diff --git a/server/internal/config/config.go b/server/internal/config/config.go index 7df1ad5..03769c5 100644 --- a/server/internal/config/config.go +++ b/server/internal/config/config.go @@ -59,14 +59,14 @@ type AuthConfig struct { } type ProxyConfig struct { - DefaultChannelName string // 首次启动自动创建的渠道名(如 openai) - UpstreamBaseURL string // 渠道 base_url 默认值 - UpstreamKey string // 渠道上游 key 默认值 - DefaultModel string // 渠道模型导入时使用的模型名 - Timeout time.Duration - HealthInterval time.Duration // 渠道健康检查周期 - HealthFailThreshold int // 连续失败 N 次进 cooldown - LogRaw bool // 记录管理员原始请求体+响应到 usage_logs(调试用,默认关) + DefaultChannelName string // 首次启动自动创建的渠道名(如 openai) + UpstreamBaseURL string // 渠道 base_url 默认值 + UpstreamKey string // 渠道上游 key 默认值 + DefaultModel string // 渠道模型导入时使用的模型名 + Timeout time.Duration + HealthInterval time.Duration // 渠道健康检查周期 + HealthFailThreshold int // 连续失败 N 次进 cooldown + LogRaw bool // 记录管理员原始请求体+响应到 usage_logs(调试用,默认关) } // loadDotEnv 读取 .env 并把 KEY=VALUE 注入环境变量(AutomaticEnv 自动映射 OT_ 前缀)。 @@ -127,7 +127,7 @@ func Load() (*Config, error) { v.SetDefault("proxy.upstream_base_url", "https://api.openai.com") v.SetDefault("proxy.upstream_key", "") v.SetDefault("proxy.default_model", "gpt-4o-mini") - v.SetDefault("proxy.timeout", "120s") + v.SetDefault("proxy.timeout", "300s") v.SetDefault("proxy.health_interval", "60s") v.SetDefault("proxy.health_fail_threshold", 2) v.SetDefault("proxy.log_raw", false) diff --git a/server/internal/proxy/gateway.go b/server/internal/proxy/gateway.go index 8ab5005..b1adc47 100644 --- a/server/internal/proxy/gateway.go +++ b/server/internal/proxy/gateway.go @@ -109,7 +109,7 @@ func contains(list []string, s string) bool { return false } -func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ratelimit.Limiter, userRPS int, logRaw bool) *Gateway { +func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ratelimit.Limiter, userRPS int, logRaw bool, gw_timeout time.Duration) *Gateway { return &Gateway{ db: db, ch: channel.NewService(db, enc), @@ -118,7 +118,7 @@ func NewGateway(db *gorm.DB, enc *crypto.Encryptor, rec *usage.Recorder, lim *ra lim: lim, userRPS: userRPS, logRaw: logRaw, - hc: &http.Client{Timeout: 120 * time.Second}, + hc: &http.Client{Timeout: gw_timeout * time.Second}, } } @@ -272,10 +272,10 @@ func upstreamPath(proto string) string { // upstreamPlan 描述一次代理请求的上游访问方式。 type upstreamPlan struct { - proto string // 上游协议(用于分协议 base_url) - path string // 上游路径 - body []byte // 已转换的请求体 - lineConv func([]byte) []byte // 流式逐行转换(nil=直通) + proto string // 上游协议(用于分协议 base_url) + path string // 上游路径 + body []byte // 已转换的请求体 + lineConv func([]byte) []byte // 流式逐行转换(nil=直通) bodyConv func([]byte) ([]byte, error) // 非流式响应体转换(nil=直通) } diff --git a/server/internal/proxy/passthrough.go b/server/internal/proxy/passthrough.go index ba5fd65..40f5472 100644 --- a/server/internal/proxy/passthrough.go +++ b/server/internal/proxy/passthrough.go @@ -3,7 +3,6 @@ package proxy import ( "bufio" "bytes" - "context" "crypto/rand" "encoding/hex" "encoding/json" @@ -218,9 +217,7 @@ func (g *Gateway) proxyOne(c *gin.Context, ch *store.Channel, plan *upstreamPlan } } - ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(ch.TimeoutMS)*time.Millisecond) - defer cancel() - req, err := http.NewRequestWithContext(ctx, http.MethodPost, upstreamURL(ch, plan.proto, plan.path), bytes.NewReader(upBody)) + req, err := http.NewRequest(http.MethodPost, upstreamURL(ch, plan.proto, plan.path), bytes.NewReader(upBody)) if err != nil { return false, false, http.StatusInternalServerError, []byte("failed to build upstream request") } @@ -242,9 +239,6 @@ func (g *Gateway) proxyOne(c *gin.Context, ch *store.Channel, plan *upstreamPlan start := time.Now() resp, err := g.hc.Do(req) if err != nil { - if ctx.Err() == context.DeadlineExceeded { - return false, true, http.StatusGatewayTimeout, []byte("upstream request timed out") - } return false, true, http.StatusBadGateway, []byte("upstream request failed: " + err.Error()) } defer resp.Body.Close()