51 lines
1.3 KiB
Go
51 lines
1.3 KiB
Go
package middleware
|
||
|
||
import (
|
||
"net"
|
||
"net/http"
|
||
"strings"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/oschwald/geoip2-golang"
|
||
)
|
||
|
||
func GeoRedirect(mapping map[string]string, defaultHost string) gin.HandlerFunc {
|
||
db, err := geoip2.Open("./GeoLite2-Country/GeoLite2-Country.mmdb")
|
||
if err != nil {
|
||
// 如果打开失败,返回不执行重定向的中间件
|
||
return func(c *gin.Context) { c.Next() }
|
||
}
|
||
return func(c *gin.Context) {
|
||
defer c.Next()
|
||
// 获取真实客户端 IP(考虑代理)
|
||
ipStr := c.Request.Header.Get("X-Forwarded-For")
|
||
if ipStr == "" {
|
||
ipStr = c.ClientIP()
|
||
} else {
|
||
// X-Forwarded-For 可能是逗号分隔的列表,取第一个
|
||
ipStr = strings.TrimSpace(strings.Split(ipStr, ",")[0])
|
||
}
|
||
ip := net.ParseIP(ipStr)
|
||
if ip == nil {
|
||
return
|
||
}
|
||
record, err := db.Country(ip)
|
||
if err != nil {
|
||
return
|
||
}
|
||
iso := record.Country.IsoCode // 如 "US", "CN", "BR"
|
||
target, ok := mapping[iso]
|
||
if !ok {
|
||
target = defaultHost
|
||
}
|
||
// 如果目标域名与当前请求不同,重定向(保留路径/查询)
|
||
if target != "" && !strings.Contains(c.Request.Host, target) {
|
||
location := "https://" + target + c.Request.URL.RequestURI()
|
||
// 302 临时重定向;如需永久改用 http.StatusMovedPermanently
|
||
c.Redirect(http.StatusFound, location)
|
||
c.Abort()
|
||
return
|
||
}
|
||
}
|
||
}
|