request.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package utils
  2. import (
  3. "strings"
  4. "github.com/gin-gonic/gin"
  5. )
  6. // GetClientIP 获取客户端 IP 地址(考虑代理情况)
  7. func GetClientIP(c *gin.Context) string {
  8. // 优先从 X-Forwarded-For 获取(适用于代理/负载均衡)
  9. // 标准格式为「客户端, 代理1, 代理2」;数据库存 varchar 时整串会超长,只取第一项。
  10. xff := strings.TrimSpace(c.GetHeader("X-Forwarded-For"))
  11. if xff != "" {
  12. if first := firstXForwardedForClient(xff); first != "" {
  13. return sanitizeIPForDB(first)
  14. }
  15. }
  16. ip := strings.TrimSpace(c.GetHeader("X-Real-IP"))
  17. if ip != "" {
  18. return sanitizeIPForDB(ip)
  19. }
  20. return sanitizeIPForDB(c.ClientIP())
  21. }
  22. func firstXForwardedForClient(xff string) string {
  23. for _, part := range strings.Split(xff, ",") {
  24. s := strings.TrimSpace(part)
  25. if s != "" {
  26. return s
  27. }
  28. }
  29. return ""
  30. }
  31. // sanitizeIPForDB 限制长度,避免异常头或未来字段变更再次撑爆列。
  32. func sanitizeIPForDB(ip string) string {
  33. ip = strings.TrimSpace(ip)
  34. const maxLen = 255
  35. if len(ip) > maxLen {
  36. return ip[:maxLen]
  37. }
  38. return ip
  39. }
  40. // ParseUserAgent 从 User-Agent 字符串中解析浏览器和操作系统
  41. func ParseUserAgent(userAgent string) (browser string, os string) {
  42. browser = "Unknown"
  43. os = "Unknown"
  44. ua := strings.ToLower(userAgent)
  45. if ua == "" {
  46. return
  47. }
  48. switch {
  49. case strings.Contains(ua, "edg/"):
  50. browser = "Edge"
  51. case strings.Contains(ua, "chrome/"):
  52. browser = "Chrome"
  53. case strings.Contains(ua, "firefox/"):
  54. browser = "Firefox"
  55. case strings.Contains(ua, "safari/"):
  56. browser = "Safari"
  57. }
  58. switch {
  59. case strings.Contains(ua, "windows nt"):
  60. os = "Windows"
  61. case strings.Contains(ua, "mac os x") || strings.Contains(ua, "macintosh"):
  62. os = "macOS"
  63. case strings.Contains(ua, "android"):
  64. os = "Android"
  65. case strings.Contains(ua, "iphone") || strings.Contains(ua, "ipad"):
  66. os = "iOS"
  67. case strings.Contains(ua, "linux"):
  68. os = "Linux"
  69. }
  70. return
  71. }