feat(api-gateway): admin 路由组 + BFF 路径重写 + announcements 路由 + Dockerfile 修复 + nextstep v2 文档
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -79,12 +80,15 @@ func main() {
|
||||
// iam 服务路由(身份与访问管理)
|
||||
registerProxy(api, "iam", cfg.IamServiceURL)
|
||||
// teacher-bff 路由(教师聚合层 GraphQL)
|
||||
registerProxy(api, "teacher", cfg.TeacherBffURL)
|
||||
// BFF 在 /graphql 提供服务(@Controller("graphql")),需剥离 /api/v1/teacher 前缀
|
||||
// 契约 student-portal_contract.md §2.3:/api/v1/{bff}/* → {bff}:port/*
|
||||
registerBffProxy(api, "teacher", cfg.TeacherBffURL)
|
||||
// student-bff 路由(学生聚合层 GraphQL,P3)
|
||||
registerProxy(api, "student", cfg.StudentBffURL)
|
||||
registerBffProxy(api, "student", cfg.StudentBffURL)
|
||||
// parent-bff 路由(家长聚合层 GraphQL,P4)
|
||||
registerProxy(api, "parent", cfg.ParentBffURL)
|
||||
// core-edu 域路由(考试/作业/成绩)
|
||||
// parent-bff 在 /v1/graphql 提供服务(ARB-022 §24.4 ISSUE-003 方案 A)
|
||||
registerBffProxy(api, "parent", cfg.ParentBffURL)
|
||||
// core-edu 域路由(考试/作业/成绩)—— 下游 controller 在 /v1/{domain}/*,仅需剥离 /api
|
||||
registerProxy(api, "exams", cfg.CoreEduServiceURL)
|
||||
registerProxy(api, "homework", cfg.CoreEduServiceURL)
|
||||
registerProxy(api, "grades", cfg.CoreEduServiceURL)
|
||||
@@ -93,9 +97,12 @@ func main() {
|
||||
registerProxy(api, "chapters", cfg.ContentServiceURL)
|
||||
registerProxy(api, "knowledge-points", cfg.ContentServiceURL)
|
||||
registerProxy(api, "questions", cfg.ContentServiceURL)
|
||||
// msg 域路由(通知/消息)
|
||||
// msg 域路由(通知/消息/公告)
|
||||
registerProxy(api, "notifications", cfg.MsgServiceURL)
|
||||
registerProxy(api, "messages", cfg.MsgServiceURL)
|
||||
// announcements 路由:msg 公告 REST API(msg nextstep.md §2.5 要求)
|
||||
// /api/v1/announcements/* → msg:3007/v1/announcements/*
|
||||
registerProxy(api, "announcements", cfg.MsgServiceURL)
|
||||
// ai 服务路由(AI 聊天/生成/优化)
|
||||
registerProxy(api, "ai", cfg.AiServiceURL)
|
||||
// data-ana 域路由(学情诊断/错题本/仪表盘)
|
||||
@@ -103,6 +110,27 @@ func main() {
|
||||
registerProxy(api, "dashboard", cfg.DataAnaServiceURL)
|
||||
}
|
||||
|
||||
// admin 路由组:admin-portal 入口(契约 admin-portal_contract.md §2.3)
|
||||
// POST /api/admin/graphql → teacher-bff:3003/graphql(admin 命名空间)
|
||||
// 中间件链:熔断 → JWT 鉴权 → admin 角色强制 → 指标 → 反向代理
|
||||
admin := r.Group("/api/admin")
|
||||
admin.Use(middleware.CircuitBreaker("teacher-bff-admin"))
|
||||
admin.Use(middleware.AuthMiddleware(cfg, fetcher))
|
||||
admin.Use(middleware.AdminRoleMiddleware())
|
||||
admin.Use(observability.Metrics())
|
||||
{
|
||||
// /api/admin/graphql 是唯一入口(契约 §2.3 要求),
|
||||
// 路径重写:/api/admin/graphql → /graphql(teacher-bff @Controller("graphql"))
|
||||
graphqlProxy, err := proxy.NewProxyRewrite(cfg.TeacherBffURL, func(p string) string {
|
||||
return strings.TrimPrefix(p, "/api/admin")
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to create admin graphql proxy", "target", cfg.TeacherBffURL, "error", err)
|
||||
panic(err)
|
||||
}
|
||||
admin.Any("/graphql", proxy.ProxyHandler(graphqlProxy))
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: ":" + cfg.Port,
|
||||
Handler: r,
|
||||
@@ -139,6 +167,8 @@ func main() {
|
||||
|
||||
// registerProxy 创建反向代理并注册无尾斜杠与通配符两条路由。
|
||||
// RedirectTrailingSlash=false 时 Gin 不会自动跳转,故两条路由都要显式注册。
|
||||
// 适用于下游 controller 路径含 /v1 前缀的服务(iam/core-edu/content/msg/ai/data-ana):
|
||||
// /api/v1/{prefix}/* → 剥离 /api → /v1/{prefix}/* 转发下游。
|
||||
func registerProxy(api *gin.RouterGroup, prefix, targetURL string) {
|
||||
p, err := proxy.NewProxy(targetURL)
|
||||
if err != nil {
|
||||
@@ -149,3 +179,23 @@ func registerProxy(api *gin.RouterGroup, prefix, targetURL string) {
|
||||
api.Any("/"+prefix, handler)
|
||||
api.Any("/"+prefix+"/*path", handler)
|
||||
}
|
||||
|
||||
// registerBffProxy 创建带路径重写的反向代理,用于 BFF 路由(teacher/student/parent)。
|
||||
// BFF 在 /graphql 或 /v1/graphql 提供服务(@Controller),与下游 controller 在 /v1/{domain}/* 的
|
||||
// 非 BFF 服务不同,需剥离 /api/v1/{prefix} 前缀,仅转发剩余路径到下游。
|
||||
// 例:/api/v1/teacher/graphql → /graphql(teacher-bff:3003/graphql)。
|
||||
// 例:/api/v1/parent/v1/graphql → /v1/graphql(parent-bff:3010/v1/graphql,ARB-022 §24.4 ISSUE-003 方案 A)。
|
||||
// 契约依据:student-portal_contract.md §2.3 /api/v1/{bff}/* → {bff}:port/*
|
||||
func registerBffProxy(api *gin.RouterGroup, prefix, targetURL string) {
|
||||
stripPrefix := "/api/v1/" + prefix
|
||||
p, err := proxy.NewProxyRewrite(targetURL, func(p string) string {
|
||||
return strings.TrimPrefix(p, stripPrefix)
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to create bff proxy", "prefix", prefix, "target", targetURL, "error", err)
|
||||
panic(err)
|
||||
}
|
||||
handler := proxy.ProxyHandler(p)
|
||||
api.Any("/"+prefix, handler)
|
||||
api.Any("/"+prefix+"/*path", handler)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user