mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 08:31:55 +08:00
feat(internal/handler): add logging and streaming for proxy handler
This commit is contained in:
parent
39605e0033
commit
3ea86189b1
@ -3,9 +3,15 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultBufferSize = 32 * 1024 // 32KB
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProxyHandler struct {
|
type ProxyHandler struct {
|
||||||
@ -19,10 +25,14 @@ func NewProxyHandler(pathMap map[string]string) *ProxyHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
// 处理根路径请求
|
// 处理根路径请求
|
||||||
if r.URL.Path == "/" {
|
if r.URL.Path == "/" {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprint(w, "Welcome to CZL proxy.")
|
fmt.Fprint(w, "Welcome to CZL proxy.")
|
||||||
|
log.Printf("[%s] %s %s -> %d (root path) [%v]",
|
||||||
|
getClientIP(r), r.Method, r.URL.Path, http.StatusOK, time.Since(startTime))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +50,8 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 如果没有匹配的路径,返回 404
|
// 如果没有匹配的路径,返回 404
|
||||||
if matchedPrefix == "" {
|
if matchedPrefix == "" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
|
log.Printf("[%s] %s %s -> 404 (not found) [%v]",
|
||||||
|
getClientIP(r), r.Method, r.URL.Path, time.Since(startTime))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +63,8 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body)
|
proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Error creating proxy request", http.StatusInternalServerError)
|
http.Error(w, "Error creating proxy request", http.StatusInternalServerError)
|
||||||
|
log.Printf("[%s] %s %s -> 500 (error: %v) [%v]",
|
||||||
|
getClientIP(r), r.Method, r.URL.Path, err, time.Since(startTime))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +80,8 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
resp, err := client.Do(proxyReq)
|
resp, err := client.Do(proxyReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Error forwarding request", http.StatusBadGateway)
|
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
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -76,11 +92,41 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 设置响应状态码
|
// 设置响应状态码
|
||||||
w.WriteHeader(resp.StatusCode)
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
|
||||||
// 复制响应体
|
// 使用流式传输复制响应体
|
||||||
if _, err := io.Copy(w, resp.Body); err != nil {
|
var bytesCopied int64
|
||||||
// 这里只记录错误,不返回给客户端,因为响应头已经发送
|
if f, ok := w.(http.Flusher); ok {
|
||||||
fmt.Printf("Error copying response: %v\n", err)
|
buf := make([]byte, defaultBufferSize)
|
||||||
|
for {
|
||||||
|
n, rerr := resp.Body.Read(buf)
|
||||||
|
if n > 0 {
|
||||||
|
bytesCopied += int64(n)
|
||||||
|
_, werr := w.Write(buf[:n])
|
||||||
|
if werr != nil {
|
||||||
|
log.Printf("Error writing response: %v", werr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
if rerr == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if rerr != nil {
|
||||||
|
log.Printf("Error reading response: %v", rerr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不支持 Flusher,使用普通的 io.Copy
|
||||||
|
bytesCopied, err = io.Copy(w, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error copying response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录访问日志
|
||||||
|
log.Printf("[%s] %s %s -> %s -> %d (%d bytes) [%v]",
|
||||||
|
getClientIP(r), r.Method, r.URL.Path, targetURL,
|
||||||
|
resp.StatusCode, bytesCopied, time.Since(startTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyHeader(dst, src http.Header) {
|
func copyHeader(dst, src http.Header) {
|
||||||
@ -92,14 +138,12 @@ func copyHeader(dst, src http.Header) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getClientIP(r *http.Request) string {
|
func getClientIP(r *http.Request) string {
|
||||||
// 检查各种可能的请求头
|
|
||||||
if ip := r.Header.Get("X-Real-IP"); ip != "" {
|
if ip := r.Header.Get("X-Real-IP"); ip != "" {
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
|
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
|
||||||
return strings.Split(ip, ",")[0]
|
return strings.Split(ip, ",")[0]
|
||||||
}
|
}
|
||||||
// 从RemoteAddr获取
|
|
||||||
if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user