# 3.11 常见问题与排错 :::tip 概述 本节收录模块开发阶段的高频问题,按「路由/编译/数据/权限/生成器」分组。更多通用排障见 [附录 A](../appendix/faq)。 ::: ## 路由与注册 ### Q:新增接口 404 排查顺序: ```text 1. router.go 是否有 Bind(s, new(controller.CXxx)) 注册行(生成器会自动写) 2. 请求结构体是否内嵌 gmeta.Meta 且 method/path 标签正确 3. 控制器方法签名是否为 (ctx, *v1.XxxReq) (*v1.XxxRes, error)——签名不符静默跳过 4. 路径是否误带 /v1(本项目 URL 无版本段) ``` 验证:`curl http://127.0.0.1:8000/api.json | grep "xxx"`——gmeta 会补注册进 OpenAPI。 ### Q:取用 service panic `implement not found` logic 的 `init()` 未调用 `service.RegisterXxx`,或接口文件的取用函数名与注册函数名不匹配。检查三件套(接口/取用/注册)拼写一致。 ## 编译与结构 ### Q:`go build` 报 logic 循环引用 logic 是单包,跨模块直接调用包级函数即可,不要在 logic 内 import 其他会 import logic 的包。依赖红线:`task → logic` 单向允许;`logic → task` 禁止;middleware 经 wire.go 函数变量接线(不 import 业务包)。 ### Q:改动 logic 方法签名后编译通过但运行 403/空响应 service 接口是手工维护的——签名变更必须同步 `internal/service/{模块}.go`,否则 controller 调用的是旧接口(编译期不报错的场景是接口方法恰好同签名但语义变化)。 ### Q:新增了字段但接口返回里没有 三处都要检查:entity 是否刷新(`gf gen dao`)→ Req/Res 结构体是否含该字段 → ToData 是否映射(写侧)。读侧展示字段在 Item/DetailRes 声明即可(Struct 自动映射)。 ## 数据与隔离 ### Q:新增数据 tenant_id 为 0 或报错 租户级表必须把表名加入 `internal/model/hooks/hooks.go` 的 `tenantTables` 清单(生成器不自动维护)。插入行为:租户用户零值自动填自身;超管未指定填 `tenant.defaultId`;显式 0 建平台共享行。 ### Q:查询结果包含已删除数据 是否绕过了 `dao.{X}.Ctx(ctx)` 直连 `g.DB()`?红线:唯一查询入口是 dao.Ctx,它自动注入 `del_flag=0`。 ### Q:唯一校验漏报 1062 或跨租户误报 `UniqueFields` 的 `Group` 范围必须等于唯一索引范围:索引含 tenant_id 时必须 `Group:"tenant_id"`。手写检查(如 user 的 username/mobile)按"被改行现租户"校验。 ### Q:删除报"存在下级或关联" 模块 BeforeDelete 守卫(如 dept 有子级/用户、user 关联清理 user_role)。这是业务保护,需要先处理关联数据。 ## 权限与日志 ### Q:新接口一直 403 ```text 1. gmeta permission 标签是否声明(空则仅需登录) 2. 菜单里权限节点是否存在(sys:{module小驼峰}:{action}) 3. 角色是否勾选该节点并保存(保存会清身份缓存) 4. 测试账号是否重新登录(身份缓存 300s;可 DEL easygoadmin:user:identity:{uid}) ``` ### Q:操作日志没记录 检查:gmeta `log` 标签是否为空(空不记录);`logType:"query"` 且 `operationLog.logQuery: false` 时查询类跳过;`operationLog.enable` 总开关;通道满会丢弃(每丢 100 条告警一次)。 ## 生成器 ### Q:生成器不创建字典 枚举注释格式不对——须为 `字段名:1-正常 2-禁用` 形式(`-`/`—`/`=`/`=` 分隔)。非 MySQL 库内省不到注释,建议在 MySQL 上生成。 ### Q:生成的前端页面路由 404 菜单由生成器创建(path `/{domain}/{moduleCamel}`),但角色未勾选新菜单;或 component 路径与实际文件不符(domain 归属由 genDomainMap 决定)。 ### Q:重复生成会覆盖我的手工修改吗 默认不会——`generator.overwrite: false` 时已存在文件跳过(计入 Skipped)。`overwrite: true` 时全部覆盖(计入 Overwritten),批量覆盖前务必备份或临时改回 false。 ### Q:租户级新表生成后数据不隔离 生成器不维护 `tenantTables` 清单,需手工把表名加入 `internal/model/hooks/hooks.go` 后重启。