如何在Golang中实现获取用户IP的Chi全局中间件
实现Chi框架全局IP获取中间件
1. 定义上下文键(避免冲突)
先声明一个自定义的上下文键,用于存储客户端IP,防止和其他上下文值产生命名冲突:
type ipContextKey struct{} var ClientIPKey = ipContextKey{}
2. 封装为Chi兼容的中间件
将你的IP获取逻辑包装成符合Chi中间件规范的函数,中间件会先获取IP并存入请求上下文,再传递给后续处理器:
import ( "context" "net/http" "strings" ) // ClientIPMiddleware 全局获取客户端IP的中间件 func ClientIPMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { clientIp := r.Header.Get("X-FORWARDED-FOR") if clientIp != "" { // 处理多IP场景(反向代理下可能用逗号分隔) ips := strings.Split(clientIp, ",") for _, ip := range ips { trimmedIp := strings.TrimSpace(ip) if trimmedIp != "" { clientIp = trimmedIp break } } } else { clientIp = r.RemoteAddr // 去掉RemoteAddr中的端口部分(默认格式为IP:端口) if idx := strings.Index(clientIp, ":"); idx != -1 { clientIp = clientIp[:idx] } } // 将IP存入请求上下文 ctx := context.WithValue(r.Context(), ClientIPKey, clientIp) // 传递携带IP的请求给后续处理器 next.ServeHTTP(w, r.WithContext(ctx)) }) }
3. 在routes.go中全局注册中间件
在路由初始化时,通过Chi.Use()将中间件注册为全局生效,和Logger等中间件用法一致:
import "github.com/go-chi/chi/v5" func SetupRoutes() *chi.Mux { r := chi.NewRouter() // 全局注册IP中间件 r.Use(ClientIPMiddleware) // 可同时注册其他全局中间件 r.Use(chi.Logger) // 定义业务路由 r.Get("/", homeHandler) r.Get("/user", userHandler) return r }
4. 在业务处理器中获取IP
后续所有处理器都可以直接从请求上下文中取出IP,无需重复调用获取逻辑:
func homeHandler(w http.ResponseWriter, r *http.Request) { clientIP, ok := r.Context().Value(ClientIPKey).(string) if !ok { clientIP = "unknown" } w.Write([]byte("你的IP地址:" + clientIP)) }
注意事项
- 如果服务部署在反向代理(如Nginx、Cloudflare)后,需确保代理服务器正确传递
X-FORWARDED-FOR请求头,否则获取到的会是代理服务器的IP。
内容的提问来源于stack exchange,提问作者Radin Khosraviani
相关产品推荐
相关产品推荐

