chore(api-gateway): merge api-gateway module into main
Merge feat/api-gateway-ai01 into main, conflicts resolved in favor of feature branch
This commit is contained in:
@@ -195,21 +195,30 @@
|
||||
|
||||
### 2.1 api-gateway(Go)
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| P1 鉴权 | Gateway 内置 HS256 JWT,`jwt.ParseWithClaims` + `SigningMethodHMAC` 校验 |
|
||||
| P2 鉴权升级 | 改 RS256,IAM 私钥签发,Gateway 公钥校验,无需调 IAM |
|
||||
| 路由转发 | `gin.Group("/api/v1")` + `httputil.NewSingleHostReverseProxy` |
|
||||
| 路径重写 | 去掉 `/api/v1` 前缀后转发到下游服务 |
|
||||
| 用户上下文注入 | `c.Request.Header.Set("x-user-id", claims.UserID)` 传递给下游 |
|
||||
| 请求 ID | Gateway 生成或透传 `X-Request-ID`,`c.Set("request_id", ...)` + `c.Header(...)` |
|
||||
| P1 不做 | 限流/熔断/灰度(P6 硬化阶段实现) |
|
||||
| 健康检查 | `GET /health` 无需鉴权 |
|
||||
| 尾斜杠重定向循环 | `r.RedirectTrailingSlash=false` + 同时注册 `Any("/classes")` 与 `Any("/classes/*path")` |
|
||||
| 开发模式鉴权旁路 | `DEV_MODE=true` 时接受 `Bearer dev-token`,注入固定身份;生产必须 `false` |
|
||||
| 路由注册位置 | 真实路由在 `main.go` 的 `api.Group` 内注册,`internal/routing/routing.go` 若未被 main 引用即为死代码 |
|
||||
| 多服务路由扩展 | 新增服务代理时在 main.go 注册两组路由:`Any("/x")` + `Any("/x/*path")`,与 classes 一致 |
|
||||
| DEV_MODE 环境变量 | Go 不自动加载 .env,`DEV_MODE` 必须在启动前 export 或写入系统环境变量,否则 DevMode=false 导致 dev-token 被拒 |
|
||||
| 场景 | 技术/规则 |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| P2 鉴权(RS256) | `shared-go/jwks.Fetcher` 拉 IAM `/.well-known/jwks.json` 公钥,TTL 5min 缓存,`jwt.Parse` 用公钥验签 |
|
||||
| 路由转发 | `gin.Group("/api/v1")` + `httputil.NewSingleHostReverseProxy` |
|
||||
| 路径重写 | 去掉 `/api/v1` 前缀后转发到下游服务(方案 B:Gateway 不改路径,各服务 Controller 内加 `/v1`) |
|
||||
| 用户上下文注入 | `c.Request.Header.Set("x-user-id/x-user-roles/x-data-scope", ...)` 传递给下游 |
|
||||
| 请求 ID | Gateway 生成或透传 `X-Request-Id`(`req-<uuid-v4>` 格式),`c.Set("request_id", ...)` + `c.Header(...)` |
|
||||
| 限流 | per-IP 令牌桶(`sync.Map`),超限 429 `GW_RATE_LIMITED`;P6 迁 Redis 支持多副本 |
|
||||
| 熔断 | `gobreaker v2` 共享 downstream 实例,5xx > 50% 触发 OPEN,返回 503 `GW_CIRCUIT_OPEN` + Retry-After |
|
||||
| 错误码 | 统一 `GW_` 前缀(W1),响应体 ActionState 信封 `{success,error:{code,message}}`(W2) |
|
||||
| 结构化日志 | 标准库 `log/slog`(W3),`slog.Info`/`slog.Error` 带 key-value;未接入 shared-go/logger(zap,待评估) |
|
||||
| 健康检查 | `GET /healthz`(liveness,无鉴权)+ `GET /readyz`(readiness,并行 ping 9 下游 /healthz,软失败规则,W4) |
|
||||
| Metrics | 7 个业务指标(promauto),`GET /metrics` 暴露(W5):requests/duration/circuit/ratelimit/proxy/jwks/authfail |
|
||||
| Tracer 资源属性 | `resource.New` 补 service.name/version/deployment.environment/host.name(W6,4 项完整) |
|
||||
| DevMode 生产防护 | 启动时 `DevMode=true && ENV=production` panic 拒绝启动(W7,config.go Load 校验) |
|
||||
| 尾斜杠重定向循环 | `r.RedirectTrailingSlash=false` + 同时注册 `Any("/classes")` 与 `Any("/classes/*path")` |
|
||||
| 开发模式鉴权旁路 | `DEV_MODE=true` 时接受 `Bearer dev-token`,注入固定身份;生产必须 `false` |
|
||||
| 路由注册位置 | 真实路由在 `main.go` 的 `api.Group` 内注册,`internal/routing/routing.go` 若未被 main 引用即为死代码 |
|
||||
| 多服务路由扩展 | 新增服务代理时用 `registerProxy(api, prefix, targetURL)` helper 注册两组路由,统一管理 |
|
||||
| DEV_MODE 环境变量 | Go 不自动加载 .env,`DEV_MODE` 必须在启动前 export 或写入系统环境变量,否则 DevMode=false 导致 dev-token 被拒 |
|
||||
| go.work workspace 解析 | `go.work` 列 `use ./packages/shared-go`,本地解析 shared-go 依赖,无需 `go mod tidy` 拉远程 |
|
||||
| go.work 版本冲突 | go.work 的 `go` 版本须 ≥ workspace 内所有模块的最高版本(push-gateway 要求 1.25.0,故 go.work 用 1.25.0) |
|
||||
| CORS 配置 | `CORS(cfg *config.Config)` 从 Config 读白名单,未配置时用开发默认白名单(localhost:3000,3001) |
|
||||
| 请求体限制 | `RequestBodyLimit` 先检 Content-Length 再用 `http.MaxBytesReader`,超限 413 `GW_REQUEST_TOO_LARGE` 信封 |
|
||||
|
||||
### 2.2 classes(TS/NestJS,P1 黄金模板)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user