diff --git a/internal/handler/proxy.go b/internal/handler/proxy.go index 376f6f2..ea53a0b 100644 --- a/internal/handler/proxy.go +++ b/internal/handler/proxy.go @@ -128,13 +128,6 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } defer resp.Body.Close() - // 设置正确的 Content-Type - if strings.HasSuffix(strings.ToLower(decodedPath), ".mp4") { - w.Header().Set("Content-Type", "video/mp4") - } else if ct := resp.Header.Get("Content-Type"); ct != "" { - w.Header().Set("Content-Type", ct) - } - copyHeader(w.Header(), resp.Header) // 设置响应状态码 @@ -172,9 +165,9 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // 记录访问日志 - log.Printf("[%s] %s %s -> %s -> %d (%d bytes) [%v]", + log.Printf("[%s] %s %s -> %s -> %d (%s) [%v]", getClientIP(r), r.Method, r.URL.Path, targetURL, - resp.StatusCode, bytesCopied, time.Since(startTime)) + resp.StatusCode, formatBytes(bytesCopied), time.Since(startTime)) } func copyHeader(dst, src http.Header) { @@ -197,3 +190,19 @@ func getClientIP(r *http.Request) string { } return r.RemoteAddr } + +func formatBytes(bytes int64) string { + const ( + MB = 1024 * 1024 + KB = 1024 + ) + + switch { + case bytes >= MB: + return fmt.Sprintf("%.2f MB", float64(bytes)/MB) + case bytes >= KB: + return fmt.Sprintf("%.2f KB", float64(bytes)/KB) + default: + return fmt.Sprintf("%d Bytes", bytes) + } +} diff --git a/internal/middleware/fixed_path_proxy.go b/internal/middleware/fixed_path_proxy.go index 9767c0b..0d414ae 100644 --- a/internal/middleware/fixed_path_proxy.go +++ b/internal/middleware/fixed_path_proxy.go @@ -1,12 +1,16 @@ package middleware import ( + "errors" + "fmt" "io" "log" "net" "net/http" "proxy-go/internal/config" "strings" + "syscall" + "time" ) type FixedPathConfig struct { @@ -18,6 +22,7 @@ type FixedPathConfig struct { func FixedPathProxyMiddleware(configs []config.FixedPathConfig) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + startTime := time.Now() // 添加时间记录 // 检查是否匹配任何固定路径 for _, cfg := range configs { if strings.HasPrefix(r.URL.Path, cfg.Path) { @@ -28,6 +33,8 @@ func FixedPathProxyMiddleware(configs []config.FixedPathConfig) func(http.Handle proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body) if err != nil { http.Error(w, "Error creating proxy request", http.StatusInternalServerError) + log.Printf("[%s] %s %s -> 500 (error creating request: %v) [%v]", + getClientIP(r), r.Method, r.URL.Path, err, time.Since(startTime)) return } @@ -49,6 +56,8 @@ func FixedPathProxyMiddleware(configs []config.FixedPathConfig) func(http.Handle resp, err := client.Do(proxyReq) if err != nil { http.Error(w, "Error forwarding request", http.StatusBadGateway) + log.Printf("[%s] %s %s -> 502 (proxy error: %v) [%v]", + getClientIP(r), r.Method, r.URL.Path, err, time.Since(startTime)) return } defer resp.Body.Close() @@ -64,10 +73,16 @@ func FixedPathProxyMiddleware(configs []config.FixedPathConfig) func(http.Handle w.WriteHeader(resp.StatusCode) // 复制响应体 - if _, err := io.Copy(w, resp.Body); err != nil { - // 已经发送了响应头,只能记录错误 - log.Printf("Error copying response: %v", err) + bytesCopied, err := io.Copy(w, resp.Body) + if err := handleCopyError(err); err != nil { + log.Printf("[%s] Error copying response: %v", getClientIP(r), err) } + + // 记录成功的请求 + log.Printf("[%s] %s %s -> %s -> %d (%s) [%v]", + getClientIP(r), r.Method, r.URL.Path, targetURL, + resp.StatusCode, formatBytes(bytesCopied), time.Since(startTime)) + return } } @@ -91,3 +106,36 @@ func getClientIP(r *http.Request) string { } return r.RemoteAddr } + +func handleCopyError(err error) error { + if err == nil { + return nil + } + + // 忽略常见的连接关闭错误 + if errors.Is(err, syscall.EPIPE) || // broken pipe + errors.Is(err, syscall.ECONNRESET) || // connection reset by peer + strings.Contains(err.Error(), "broken pipe") || + strings.Contains(err.Error(), "connection reset by peer") { + return nil + } + + return err +} + +// formatBytes 将字节数转换为可读的格式(MB/KB/Bytes) +func formatBytes(bytes int64) string { + const ( + MB = 1024 * 1024 + KB = 1024 + ) + + switch { + case bytes >= MB: + return fmt.Sprintf("%.2f MB", float64(bytes)/MB) + case bytes >= KB: + return fmt.Sprintf("%.2f KB", float64(bytes)/KB) + default: + return fmt.Sprintf("%d Bytes", bytes) + } +}