feat: 自适应测速时长(阶段最短5秒,负载翻倍至512MB)+ 公网IP探测与内网标注

This commit is contained in:
dsh
2026-08-17 09:39:54 -04:00
parent 3b48eea5d1
commit 7794743828
4 changed files with 187 additions and 51 deletions
+32 -4
View File
@@ -91,12 +91,14 @@ func maskIP(ip string) string {
return ip
}
// Ping 延迟探测:返回最小响应,供前端计算 RTT
// Ping 延迟探测:返回最小响应,供前端计算 RTT;同时回传服务器看到的客户端 IP
// (NAT 环境下可能是内网 IP,前端会用公网探测结果替代)
func (h *Handler) Ping(c *gin.Context) {
c.Header("Cache-Control", "no-store")
c.JSON(http.StatusOK, gin.H{
"pong": true,
"ts": time.Now().UnixMilli(),
"pong": true,
"ts": time.Now().UnixMilli(),
"client_ip": clientIP(c),
})
}
@@ -177,6 +179,7 @@ type resultReq struct {
JitterMs float64 `json:"jitter_ms"`
DownloadMbps float64 `json:"download_mbps"`
UploadMbps float64 `json:"upload_mbps"`
ClientIP string `json:"client_ip"` // 可选:前端探测到的公网出口 IP
}
// Result 保存一次测速结果
@@ -196,8 +199,15 @@ func (h *Handler) Result(c *gin.Context) {
return
}
// 客户端 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)
}
record := &db.SpeedTestResult{
ClientIP: clientIP(c),
ClientIP: ip,
LatencyMs: req.LatencyMs,
JitterMs: req.JitterMs,
DownloadMbps: req.DownloadMbps,
@@ -215,6 +225,7 @@ func (h *Handler) Result(c *gin.Context) {
type RankItem struct {
ID uint `json:"id"`
ClientIP string `json:"client_ip"`
IsPrivateIP bool `json:"is_private_ip"` // NAT/内网环境(如路由器网关),前端标注展示
LatencyMs float64 `json:"latency_ms"`
JitterMs float64 `json:"jitter_ms"`
DownloadMbps float64 `json:"download_mbps"`
@@ -222,12 +233,29 @@ type RankItem struct {
CreatedAt string `json:"created_at"`
}
// isPrivateIP 判断 IP 是否为内网/保留地址(NAT 网关、局域网、回环等)
func isPrivateIP(ip string) bool {
parsed := net.ParseIP(ip)
if parsed == nil {
return true
}
if parsed.IsLoopback() || parsed.IsLinkLocalUnicast() || parsed.IsLinkLocalMulticast() {
return true
}
if parsed.IsPrivate() || parsed.IsUnspecified() {
return true
}
// IPv4 兼容段(IsPrivate 已覆盖 10/8、172.16/12、192.168/16
return false
}
func toRankItems(rows []db.SpeedTestResult) []RankItem {
items := make([]RankItem, 0, len(rows))
for _, r := range rows {
items = append(items, RankItem{
ID: r.ID,
ClientIP: maskIP(r.ClientIP),
IsPrivateIP: isPrivateIP(r.ClientIP),
LatencyMs: r.LatencyMs,
JitterMs: r.JitterMs,
DownloadMbps: r.DownloadMbps,