# 4.4 反射元数据驱动机制 :::tip 概述 本项目最核心的机制:**RouteSpec 表即路由定义**。`router.Bind` 反射扫描控制器方法,按声明注册路由并写入进程内路由元数据表,权限校验、操作日志、公开白名单、OpenAPI 四个消费方读同一份数据。 ::: ## 为什么这样设计 传统做法中路由、权限注解、日志注解分散在三处,漏配一处就出安全洞。本项目把它们收敛为一条声明: ```go "Page": {Method: "GET", Path: "/api/dept/page", Summary: "部门分页", Permission: "sys:dept:page", Log: "部门管理-查询分页记录", LogType: "query"}, ``` 一条声明同时回答:路由怎么注册、谁可以访问、记不记日志、记什么类型。 ## Bind 执行流程 ```text registerControllers 内 Bind(rg, new(handler.CXxx), map[string]RouteSpec{...}) │ ▼ 反射取控制器类型的方法集(含导出方法) │ ▼ 按签名过滤:func (c *CXxx) M(ctx context.Context, req *dto.XxxReq) (*dto.XxxRes, error) │ 签名不匹配 → 跳过(表现为 404,启动期即定) ▼ 按方法名查 RouteSpec 表 → 逐条 rg.Handle(Method, Path, 包装函数) │ ▼ 包装函数(请求期): UnmarshalBody 逃生舱判断 → 绑定写入 query→body→path → binding 校验 → 调 handler 方法 → response 信封写出 │ ▼ meta.Register 写入路由元数据表(进程内 map,读写锁保护) ``` ## 元数据表(RouteMeta) ```go // internal/router/meta/meta.go type RouteMeta struct { Method string // GET/POST/PUT/DELETE Path string // 路由模板 Summary string // OpenAPI 摘要 Permission string // 权限节点;空=登录即可 Log string // 日志标题;空=不记录 LogType string // query/add/update/delete/import/export/reset Public bool // 免登录 ReqType reflect.Type // 请求类型(文档 schema 反射用) ResType reflect.Type // 响应类型 } ``` 存储为进程内内存表(`map["GET /api/dept/page"]RouteMeta` + RWMutex),启动期写入、请求期只读,无持久化与跨进程同步——生命周期与进程一致。 ## 四个消费方(同源) | 消费方 | 读什么 | 行为 | |---|---|---| | authz 中间件 | Permission | 校验当前用户权限点集合是否命中;空则只要登录 | | operation_log 中间件 | Log / LogType | 采集请求摘要异步落库;query 类受 logQuery 开关控制 | | public 判断 | Public | IsPublicRequest 免登录放行(配合基础设施白名单) | | OpenAPI 生成 | 全部 + ReqType/ResType | /api.json 与 /swagger 端点按元数据生成文档 | 任一消费方都不再自己维护清单——声明改一处,四处同步生效。 ## 绑定细节 - **写入顺序** query → body → path,后写覆盖 → 最终优先级 path > body > query - **校验** 读 binding 标签,错误消息取 msg 标签,失败直接信封返回 - **逃生舱** 结构体实现 `UnmarshalBody(c *gin.Context) error` 则跳过默认解析(文件上传) ## 基础设施白名单(不经元数据) `internal/middleware/public.go` 维护少量不经 Bind 注册的免登录路径: ```text /api/health 健康检查 /api.json, /swagger* 文档端点(api.docs 开关) /metrics 指标端点(api.metrics 开关) ``` 业务路由的公开判断一律走元数据表,两个来源在 `IsPublicRequest` 汇合。 ## 对开发的影响 | 场景 | 做法 | |---|---| | 新增接口 | RouteSpec 表加一条 + handler 加同名方法,无注解、无散落注册 | | 改权限码 | 只改声明,同步更新菜单节点 | | 排查 403 | 看元数据表的 Permission 与角色授权 | | 生成器 | 生成器自动追加 Bind 声明块——菜单/权限/路由一致性由工具保证 | ## 下一步 → [4.5 前端分层架构](/zh/architecture/frontend-layer.html)