package handler import ( "encoding/json" "log" "net/http" "proxy-go/internal/metrics" "proxy-go/internal/models" "runtime" "strings" "time" ) type Metrics struct { // 基础指标 Uptime string `json:"uptime"` ActiveRequests int64 `json:"active_requests"` TotalRequests int64 `json:"total_requests"` TotalErrors int64 `json:"total_errors"` ErrorRate float64 `json:"error_rate"` // 系统指标 NumGoroutine int `json:"num_goroutine"` MemoryUsage string `json:"memory_usage"` // 性能指标 AverageResponseTime string `json:"avg_response_time"` RequestsPerSecond float64 `json:"requests_per_second"` // 新增字段 TotalBytes int64 `json:"total_bytes"` BytesPerSecond float64 `json:"bytes_per_second"` StatusCodeStats map[string]int64 `json:"status_code_stats"` LatencyPercentiles map[string]float64 `json:"latency_percentiles"` TopPaths []models.PathMetrics `json:"top_paths"` RecentRequests []models.RequestLog `json:"recent_requests"` TopReferers []models.PathMetrics `json:"top_referers"` } func (h *ProxyHandler) MetricsHandler(w http.ResponseWriter, r *http.Request) { uptime := time.Since(h.startTime) collector := metrics.GetCollector() stats := collector.GetStats() if stats == nil { // 返回默认值而不是错误 stats = map[string]interface{}{ "uptime": uptime.String(), "active_requests": int64(0), "total_requests": int64(0), "total_errors": int64(0), "error_rate": float64(0), "num_goroutine": runtime.NumGoroutine(), "memory_usage": "0 B", "avg_response_time": "0 ms", "total_bytes": int64(0), "bytes_per_second": float64(0), "requests_per_second": float64(0), "status_code_stats": make(map[string]int64), "latency_percentiles": make([]float64, 0), "top_paths": make([]models.PathMetrics, 0), "recent_requests": make([]models.RequestLog, 0), "top_referers": make([]models.PathMetrics, 0), } } // 确保所有必要的字段都存在 metrics := Metrics{ Uptime: uptime.String(), ActiveRequests: safeInt64(stats["active_requests"]), TotalRequests: safeInt64(stats["total_requests"]), TotalErrors: safeInt64(stats["total_errors"]), ErrorRate: float64(safeInt64(stats["total_errors"])) / float64(max(safeInt64(stats["total_requests"]), 1)), NumGoroutine: safeInt(stats["num_goroutine"]), MemoryUsage: safeString(stats["memory_usage"]), AverageResponseTime: safeString(stats["avg_response_time"]), TotalBytes: safeInt64(stats["total_bytes"]), BytesPerSecond: float64(safeInt64(stats["total_bytes"])) / metrics.Max(uptime.Seconds(), 1), RequestsPerSecond: float64(safeInt64(stats["total_requests"])) / metrics.Max(uptime.Seconds(), 1), StatusCodeStats: safeStatusCodeStats(stats["status_code_stats"]), TopPaths: safePathMetrics(stats["top_paths"]), RecentRequests: safeRequestLogs(stats["recent_requests"]), TopReferers: safePathMetrics(stats["top_referers"]), } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(metrics); err != nil { log.Printf("Error encoding metrics: %v", err) } } // 辅助函数 func max(a, b int64) int64 { if a > b { return a } return b } // 修改模板,添加登录页面 var loginTemplate = ` Proxy-Go Metrics Login

Metrics Login

密码错误
` // 修改原有的 metricsTemplate,添加 token 检查 var metricsTemplate = ` Proxy-Go Metrics

Proxy-Go Metrics

基础指标

运行时间
当前活跃请求
总请求数
错误数
错误率

系统指标

Goroutine数量
内存使用

性能指标

平均响应时间
每秒请求数

流量统计

总传输字节
每传输

状态码统计

热门路径 (Top 10)

路径 请求数 错误数 平均延迟 传输大小

最近请求

时间 路径 状态 延迟 大小 客户端IP

热门引用来源 (Top 10)

来源 请求数
` // 添加认证中间件 func (h *ProxyHandler) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { auth := r.Header.Get("Authorization") if auth == "" || !strings.HasPrefix(auth, "Bearer ") { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } token := strings.TrimPrefix(auth, "Bearer ") if !h.auth.validateToken(token) { http.Error(w, "Invalid token", http.StatusUnauthorized) return } next(w, r) } } // 修改处理器 func (h *ProxyHandler) MetricsPageHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(loginTemplate)) } func (h *ProxyHandler) MetricsDashboardHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(metricsTemplate)) } func (h *ProxyHandler) MetricsAuthHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { Password string `json:"password"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return } if req.Password != h.config.Metrics.Password { http.Error(w, "Invalid password", http.StatusUnauthorized) return } token := h.auth.generateToken() h.auth.addToken(token, time.Duration(h.config.Metrics.TokenExpiry)*time.Second) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "token": token, }) } // 添加安全的类型转换辅助函数 func safeStatusCodeStats(v interface{}) map[string]int64 { if v == nil { return make(map[string]int64) } if m, ok := v.(map[string]int64); ok { return m } return make(map[string]int64) } func safePathMetrics(v interface{}) []models.PathMetrics { if v == nil { return []models.PathMetrics{} } if m, ok := v.([]models.PathMetrics); ok { return m } return []models.PathMetrics{} } func safeRequestLogs(v interface{}) []models.RequestLog { if v == nil { return []models.RequestLog{} } if m, ok := v.([]models.RequestLog); ok { return m } return []models.RequestLog{} } func safeInt64(v interface{}) int64 { if v == nil { return 0 } if i, ok := v.(int64); ok { return i } return 0 } func safeInt(v interface{}) int { if v == nil { return 0 } if i, ok := v.(int); ok { return i } return 0 } func safeString(v interface{}) string { if v == nil { return "0 B" // 返回默认值 } if s, ok := v.(string); ok { return s } return "0 B" // 返回默认值 }