diff --git a/cmd/s3-balance/main.go b/cmd/s3-balance/main.go index 458e182..a303942 100644 --- a/cmd/s3-balance/main.go +++ b/cmd/s3-balance/main.go @@ -85,6 +85,7 @@ func main() { cfg.S3API.AccessKey, cfg.S3API.SecretKey, metricsService, + cfg.S3API.ProxyMode, ) // 设置路由 diff --git a/config/config.example.yaml b/config/config.example.yaml index 79fa3f2..b943faa 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -138,9 +138,9 @@ s3api: virtual_host: false # 工作模式: - # false (默认):预签名重定向模式,客户端直接与后端存储交互 - # true:代理模式,数据通过S3 Balance服务器传输 - proxy_mode: false + # false:预签名重定向模式,客户端直接与后端存储交互 + # true (默认):代理模式,数据通过S3 Balance服务器传输 + proxy_mode: true # 是否需要认证(开发环境可设为false) auth_required: false diff --git a/internal/api/object_handler.go b/internal/api/object_handler.go index c240a3e..e755c92 100644 --- a/internal/api/object_handler.go +++ b/internal/api/object_handler.go @@ -82,9 +82,9 @@ func (h *S3Handler) handleGetObject(w http.ResponseWriter, r *http.Request, buck return } - // 默认使用预签名重定向模式,只有明确指定时才使用代理模式 - if r.URL.Query().Get("proxy") == "true" { - // 代理模式:服务器下载内容并返回给客户端 + // 根据配置决定使用代理模式还是重定向模式 + if h.proxyMode { + // 代理模式:流式传输内容给客户端 resp, err := http.Get(downloadInfo.URL) if err != nil { h.sendS3Error(w, "InternalError", "Failed to fetch object", key) @@ -92,13 +92,38 @@ func (h *S3Handler) handleGetObject(w http.ResponseWriter, r *http.Request, buck } defer resp.Body.Close() - // 复制响应头 - for k, v := range resp.Header { - w.Header()[k] = v + // 检查响应状态 + if resp.StatusCode != http.StatusOK { + w.WriteHeader(resp.StatusCode) + io.Copy(w, resp.Body) + return } - // 复制响应体 - io.Copy(w, resp.Body) + // 复制重要的响应头 + if contentType := resp.Header.Get("Content-Type"); contentType != "" { + w.Header().Set("Content-Type", contentType) + } + if contentLength := resp.Header.Get("Content-Length"); contentLength != "" { + w.Header().Set("Content-Length", contentLength) + } + if lastModified := resp.Header.Get("Last-Modified"); lastModified != "" { + w.Header().Set("Last-Modified", lastModified) + } + if etag := resp.Header.Get("ETag"); etag != "" { + w.Header().Set("ETag", etag) + } + if contentEncoding := resp.Header.Get("Content-Encoding"); contentEncoding != "" { + w.Header().Set("Content-Encoding", contentEncoding) + } + if cacheControl := resp.Header.Get("Cache-Control"); cacheControl != "" { + w.Header().Set("Cache-Control", cacheControl) + } + + // 流式复制响应体 + _, err = io.Copy(w, resp.Body) + if err != nil { + log.Printf("Error streaming response body for key %s: %v", key, err) + } } else { // 重定向模式:返回302重定向到预签名URL(默认) http.Redirect(w, r, downloadInfo.URL, http.StatusFound) diff --git a/internal/api/s3_handler.go b/internal/api/s3_handler.go index d092502..b1df841 100644 --- a/internal/api/s3_handler.go +++ b/internal/api/s3_handler.go @@ -18,6 +18,7 @@ type S3Handler struct { accessKey string secretKey string metrics *metrics.Metrics + proxyMode bool } // NewS3Handler 创建新的S3兼容API处理器 @@ -29,6 +30,7 @@ func NewS3Handler( accessKey string, secretKey string, metrics *metrics.Metrics, + proxyMode bool, ) *S3Handler { return &S3Handler{ bucketManager: bucketManager, @@ -38,6 +40,7 @@ func NewS3Handler( accessKey: accessKey, secretKey: secretKey, metrics: metrics, + proxyMode: proxyMode, } } diff --git a/internal/config/config.go b/internal/config/config.go index f21a881..9f63bf3 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -172,8 +172,8 @@ func (c *Config) SetDefaults() { if c.S3API.SecretKey == "" { c.S3API.SecretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" } - // 默认使用预签名模式(非代理模式) - c.S3API.ProxyMode = false + // 默认使用代理模式(避免302重定向) + c.S3API.ProxyMode = true c.S3API.AuthRequired = false }