feat: 排行榜标记 IP 来源(公网 IP + 内网来源 server_ip 双维度,便于调试区分设备)

This commit is contained in:
dsh
2026-08-17 09:57:36 -04:00
parent 7794743828
commit 42dd6813af
4 changed files with 58 additions and 28 deletions
+15 -3
View File
@@ -180,6 +180,7 @@ type resultReq struct {
DownloadMbps float64 `json:"download_mbps"`
UploadMbps float64 `json:"upload_mbps"`
ClientIP string `json:"client_ip"` // 可选:前端探测到的公网出口 IP
ServerIP string `json:"server_ip"` // 可选:服务器看到的来源 IP(NAT 下为内网 IP)
}
// Result 保存一次测速结果
@@ -199,15 +200,23 @@ func (h *Handler) Result(c *gin.Context) {
return
}
// 客户端 IP:优先采用前端探测的公网出口 IP(NAT 环境下服务器只能看到内网 IP);
// 客户端展示 IP:优先采用前端探测的公网出口 IP(NAT 环境下服务器只能看到内网 IP);
// 未提供或格式非法(含回环地址伪造)时回退到 Caddy 传递的 X-Real-IP
ip := strings.TrimSpace(req.ClientIP)
if parsed := net.ParseIP(ip); parsed == nil || parsed.IsLoopback() {
ip = clientIP(c)
}
// 服务器看到的来源 IP(内网 IP,用于调试区分设备):
// 未提供时回退到 Caddy 传递的 X-Real-IP
serverIP := strings.TrimSpace(req.ServerIP)
if net.ParseIP(serverIP) == nil {
serverIP = clientIP(c)
}
record := &db.SpeedTestResult{
ClientIP: ip,
ServerIP: serverIP,
LatencyMs: req.LatencyMs,
JitterMs: req.JitterMs,
DownloadMbps: req.DownloadMbps,
@@ -221,11 +230,13 @@ func (h *Handler) Result(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"ok": true, "id": record.ID})
}
// RankItem 排行榜展示条目IP 打码)
// RankItem 排行榜展示条目
// ClientIP 打码展示;ServerIP 为来源 IP(内网 IP 完整返回,供站长调试区分设备)
type RankItem struct {
ID uint `json:"id"`
ClientIP string `json:"client_ip"`
IsPrivateIP bool `json:"is_private_ip"` // NAT/内网环境(如路由器网关),前端标注展示
ServerIP string `json:"server_ip"`
IsPrivateIP bool `json:"is_private_ip"` // ClientIP 是否为内网(探测失败回退场景)
LatencyMs float64 `json:"latency_ms"`
JitterMs float64 `json:"jitter_ms"`
DownloadMbps float64 `json:"download_mbps"`
@@ -255,6 +266,7 @@ func toRankItems(rows []db.SpeedTestResult) []RankItem {
items = append(items, RankItem{
ID: r.ID,
ClientIP: maskIP(r.ClientIP),
ServerIP: r.ServerIP,
IsPrivateIP: isPrivateIP(r.ClientIP),
LatencyMs: r.LatencyMs,
JitterMs: r.JitterMs,