从 PHP 到 AI + Golang,程序员自救转型手记(五十九):前后端自定义后台入口实现

作者:袖梨 2026-08-27

这是一个系列 Blog,作者将以一个 PHP 全栈工程师的身份,利用 AI 工具(claude code、codex、deepseek、豆包等):从零开始学习 golang 语言,并最终完成 ai-go-admin(github | gitee)开源项目的制作(欢迎 star~),全程记录分享。

从 PHP 到 AI + Golang,程序员自救转型手记(五十九):前后端自定义后台入口实现

在上一期,我们进行了 “后台系统配置管理实现”,本期将完成:自定义后台入口实现

自定义后台入口实现

作为一个后台管理系统,开发者能够自定义入口还算比较重要,比如可以将 域名/admin 进入后台改为 域名/dfwef1dki,能够实现隐藏入口的目的。

服务端

先直接问问AI:我要实现 "自定义后台入口" 的功能,前端注册路由我已有方案,现在的问题是:gin 这边注册的 /admin 路由,在什么地方修改合适?能否走现有的文件配置系统?还是只能使用固定常量,所有注册 /admin 的路由的地方,都使用该常量作为前缀?是否有更好的办法?

AI 首先给出的方案也是使用 文件配置系统 实现,增加一个 app.admin_path 配置项,它说常量方案技术上可行但有一个限制:改常量需要重新编译。实际上使用配置也是需要重新编译的,因为就算配置重载了,路由也不会重新注册,要实现路由重新注册那就麻烦了,还得清理旧的路由等,没必要。

也就是说,重新编译是不可避免的,而使用文件配置系统,或者常量方式都可以实现需求。

那当然是文件配置系统,常量没有配置项方便和易管理,不过配置名由 AI 生成的 app.admin_path 改为 server.admin_base_route_path,路由路径属于 server 层面的配置,不应该放在 app 下,让 AI 开始实现。

review 时看懂了 AI 的实现思路:

以往我们的路由注册,是子模块在 init() 内调用路由注册函数,如下

funcinit() {registry.Register(func(r *gin.Engine) {repo := repoCommon.NewConfigRepository()svc := svcRoutine.NewConfigService(repo)h := handlerRoutine.NewConfigHandler(svc, repo)group := r.Group("/admin/routine/config")h.RegisterRoutes(group)})}

init() 函数会在包载入时被自动执行,而 registry.Register 函数会将传入的 路由注册函数 全部收集起来,然后系统的入口文件内会统一调用 router.Setup 完成所有路由的注册:

// Setup 遍历所有已注册的路由模块,传入 Engine 完成注册funcSetup(r *gin.Engine) {for _, fn := range registry.Routes {fn(r)}}

AI 的自定义入口思路是:先定义一个 registry.RegisterAdmin,它不是接受 Engine,而是接受一个 gin 的路由 group,我们只需要将后台的路由注册函数由 registry.Register 换为 registry.RegisterAdmin 即可:

funcinit() {registry.RegisterAdmin(func(group *gin.RouterGroup) {repo := repoAdmin.NewAdminRuleRepository()svc := svcAuth.NewAuthAdminRuleService(repo)h := handlerAuth.NewAuthAdminRuleHandler(svc)subGroup := group.Group("/auth/rule")h.RegisterRoutes(subGroup)})}

router.Setup 现在会单独注册全部的后台路由,并且为它传递 adminGroup,如下:

// Setup 遍历所有已注册的路由模块,传入 Engine 完成注册funcSetup(r *gin.Engine) {for _, fn := range registry.Routes {fn(r)}// 后台路由分组adminGroup := r.Group(config.Get().Server.AdminBaseRoutePath)// 注册全部后台路由for _, fn := range registry.AdminRoutes {fn(adminGroup)}}

额外还发现了以下细节点需额外处理:

AdminLog 中间件可以移动注册位置

以前 AdminLog 中间件是在 serve.go 中全局注册的:

// 注册管理员操作日志中间件engine.Use(middleware.AdminLog())

现在可以直接改到 router.Setup后台路由分组 上。

funcSetup(r *gin.Engine) {for _, fn := range registry.Routes {fn(r)}adminGroup := r.Group(config.Get().Server.AdminBaseRoutePath)// 注册管理员操作日志中间件adminGroup.Use(middleware.AdminLog())for _, fn := range registry.AdminRoutes {fn(adminGroup)}}

BuildCheckPath 的改动优化

BuildCheckPath 的内部会先去掉传入字符串的 /admin/ 前缀,相当于以前是写死的 admin 路由前缀字面量,现在我们要支持自定义,此处自然也应该使用变量替换,即 config.Get().Server.AdminBaseRoutePath+"/" 替换 /admin/

但 AI 实现的是 BuildCheckPath 额外接受一个 adminPath 参数,而不是自己去读 config 数据:

funcBuildCheckPath(fullPath string, adminPath string)

这里完全可以改为函数内自行读取,因为此函数本来就在 infra 文件夹内,不是 pkg 之类的公共包。

以上只是一个案例,这里让 AI 将所有适合自行读取 admin 路由前缀配置 的,全部都自行读取,不要加参数去传。

前端

前端自定义后台入口是本来就支持的,我们的 admin 路由前缀全部都是使用的 常量 ,需要修改时,调整常量值就行了。

前端请求函数修改

前端请求函数还是在请求原本的 /admin,并没有使用 admin 路由前缀常量,而在 API 请求函数里边该常量其实非常不方便,全局替换的方式更加合理,在请求封装 srcutilsrequest.ts 的拦截器中:

// 自定义后台入口支持:将请求 URL 中的 /admin 前缀替换为实际配置的后台路径// opts.replaceCustomAdminPath 默认为 trueif (opts.replaceCustomAdminPath !== false && adminBaseRoutePath !== '/admin' && /^/admin//.test(config.url!)) {config.url = config.url!.replace(/^/admin//, adminBaseRoutePath + '/')}

相关文章

精彩推荐