package proxy import ( "net/http" "net/http/httputil" "net/url" "strings" "github.com/gin-gonic/gin" ) // NewProxy 创建反向代理。 // 路径改写:去除 /api 前缀,保留 /v1 下游 controller 前缀。 // 适用于下游 controller 路径含 /v1 前缀的服务(iam/core-edu/content/msg/ai/data-ana): // /api/v1/{prefix}/* → 剥离 /api → /v1/{prefix}/* 转发下游。 func NewProxy(targetURL string) (*httputil.ReverseProxy, error) { target, err := url.Parse(targetURL) if err != nil { return nil, err } proxy := httputil.NewSingleHostReverseProxy(target) originalDirector := proxy.Director proxy.Director = func(req *http.Request) { originalDirector(req) req.URL.Path = strings.TrimPrefix(req.URL.Path, "/api") req.Host = target.Host } return proxy, nil } // NewProxyRewrite 创建带自定义路径重写的反向代理。 // 用于 BFF 路由(teacher/student/parent)和 admin 路由: // - BFF:/api/v1/{bff}/graphql → 剥离 /api/v1/{bff} → /graphql(teacher-bff/student-bff) // - BFF:/api/v1/{bff}/v1/graphql → 剥离 /api/v1/{bff} → /v1/graphql(parent-bff,ARB-022 §24.4 ISSUE-003 方案 A) // - admin:/api/admin/graphql → 剥离 /api/admin → /graphql(teacher-bff admin 命名空间) func NewProxyRewrite(targetURL string, pathRewriter func(string) string) (*httputil.ReverseProxy, error) { target, err := url.Parse(targetURL) if err != nil { return nil, err } proxy := httputil.NewSingleHostReverseProxy(target) originalDirector := proxy.Director proxy.Director = func(req *http.Request) { originalDirector(req) req.URL.Path = pathRewriter(req.URL.Path) req.Host = target.Host } return proxy, nil } // ProxyHandler 返回 Gin 处理函数 func ProxyHandler(proxy *httputil.ReverseProxy) gin.HandlerFunc { return func(c *gin.Context) { proxy.ServeHTTP(c.Writer, c.Request) } }