-
性能指标
-
-
平均响应时间
-
+
+
性能指标
+
+ 平均响应时间
+
+
+
+ 每秒请求数
+
+
-
- 每秒请求数
-
-
-
-
-
流量统计
-
- 总传输字节
-
-
-
-
每秒传输
-
+
+
流量统计
+
+ 总传输字节
+
+
+
+ 每秒传输
+
+
@@ -362,6 +375,19 @@ var metricsTemplate = `
+
+
@@ -452,6 +478,15 @@ var metricsTemplate = `
).join('');
document.querySelector('#recentRequests tbody').innerHTML = recentRequestsHtml;
+ // 更新热门引用来源
+ const topReferersHtml = data.top_referers.map(referer =>
+ '
' +
+ '' + referer.path + ' | ' +
+ '' + referer.request_count + ' | ' +
+ '
'
+ ).join('');
+ document.querySelector('#topReferers tbody').innerHTML = topReferersHtml;
+
document.getElementById('lastUpdate').textContent = '最后更新: ' + new Date().toLocaleTimeString();
}
diff --git a/internal/handler/mirror_proxy.go b/internal/handler/mirror_proxy.go
index 2fdb9ba..2a5b4cb 100644
--- a/internal/handler/mirror_proxy.go
+++ b/internal/handler/mirror_proxy.go
@@ -138,5 +138,5 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
utils.GetRequestSource(r), actualURL)
// 记录统计信息
- collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), bytesCopied, utils.GetClientIP(r))
+ collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), bytesCopied, utils.GetClientIP(r), r)
}
diff --git a/internal/handler/proxy.go b/internal/handler/proxy.go
index 9f91d6b..f536571 100644
--- a/internal/handler/proxy.go
+++ b/internal/handler/proxy.go
@@ -109,7 +109,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- // 确定���标基础URL
+ // 确定标基础URL
targetBase := pathConfig.DefaultTarget
// 检查文件扩展名
@@ -228,7 +228,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
written, _ := w.Write(body)
- collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), int64(written), utils.GetClientIP(r))
+ collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), int64(written), utils.GetClientIP(r), r)
} else {
// 大响应使用流式传输
var bytesCopied int64
@@ -274,7 +274,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
targetURL, // 目标URL
)
- collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), bytesCopied, utils.GetClientIP(r))
+ collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), bytesCopied, utils.GetClientIP(r), r)
}
}
diff --git a/internal/metrics/collector.go b/internal/metrics/collector.go
index 03fca58..568bdea 100644
--- a/internal/metrics/collector.go
+++ b/internal/metrics/collector.go
@@ -2,6 +2,7 @@ package metrics
import (
"fmt"
+ "net/http"
"runtime"
"sort"
"sync"
@@ -17,6 +18,7 @@ type Collector struct {
totalBytes atomic.Int64
latencySum atomic.Int64
pathStats sync.Map
+ refererStats sync.Map
statusStats [6]atomic.Int64
latencyBuckets [10]atomic.Int64
recentRequests struct {
@@ -45,7 +47,7 @@ func (c *Collector) EndRequest() {
atomic.AddInt64(&c.activeRequests, -1)
}
-func (c *Collector) RecordRequest(path string, status int, latency time.Duration, bytes int64, clientIP string) {
+func (c *Collector) RecordRequest(path string, status int, latency time.Duration, bytes int64, clientIP string, r *http.Request) {
// 更新总请求数
atomic.AddInt64(&c.totalRequests, 1)
@@ -88,6 +90,17 @@ func (c *Collector) RecordRequest(path string, status int, latency time.Duration
c.pathStats.Store(path, newStats)
}
+ // 更新引用来源统计
+ if referer := r.Header.Get("Referer"); referer != "" {
+ if stats, ok := c.refererStats.Load(referer); ok {
+ stats.(*PathStats).requests.Add(1)
+ } else {
+ newStats := &PathStats{}
+ newStats.requests.Add(1)
+ c.refererStats.Store(referer, newStats)
+ }
+ }
+
// 记录最近的请求
log := &RequestLog{
Time: time.Now(),
@@ -151,6 +164,33 @@ func (c *Collector) GetStats() map[string]interface{} {
pathMetrics = allPaths
}
+ // 获取Top 10引用来源
+ var refererMetrics []PathMetrics
+ var allReferers []PathMetrics
+ c.refererStats.Range(func(key, value interface{}) bool {
+ stats := value.(*PathStats)
+ if stats.requests.Load() == 0 {
+ return true
+ }
+ allReferers = append(allReferers, PathMetrics{
+ Path: key.(string),
+ RequestCount: stats.requests.Load(),
+ })
+ return true
+ })
+
+ // 按请求数排序
+ sort.Slice(allReferers, func(i, j int) bool {
+ return allReferers[i].RequestCount > allReferers[j].RequestCount
+ })
+
+ // 取前10个
+ if len(allReferers) > 10 {
+ refererMetrics = allReferers[:10]
+ } else {
+ refererMetrics = allReferers
+ }
+
return map[string]interface{}{
"uptime": uptime.String(),
"active_requests": atomic.LoadInt64(&c.activeRequests),
@@ -170,6 +210,7 @@ func (c *Collector) GetStats() map[string]interface{} {
"status_code_stats": statusStats,
"top_paths": pathMetrics,
"recent_requests": c.getRecentRequests(),
+ "top_referers": refererMetrics,
}
}
diff --git a/internal/middleware/fixed_path_proxy.go b/internal/middleware/fixed_path_proxy.go
index 0b6365a..1b7ac60 100644
--- a/internal/middleware/fixed_path_proxy.go
+++ b/internal/middleware/fixed_path_proxy.go
@@ -83,7 +83,7 @@ func FixedPathProxyMiddleware(configs []config.FixedPathConfig) func(http.Handle
}
// 记录统计信息
- collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), bytesCopied, utils.GetClientIP(r))
+ collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), bytesCopied, utils.GetClientIP(r), r)
return
}