Golang后端路由如何同时服务两个前端应用
Golang后端路由如何同时服务两个前端应用 假设我有一个面向“普通”用户的Vue应用,以及另一个用于提供管理面板的不同Vue应用。这两个应用都需要访问几乎相同的资源,但方式不同,且使用同一个后端(API)。
以下是我的应用中的一些资源:用户、项目、日期、待办事项
正如我所说,待办事项资源需要被用户和管理员以不同的方式访问:
- 如果我是用户(用户前端),则返回我的待办事项
- 返回某个用户的所有待办事项(管理前端)
- 返回某个项目的所有待办事项(管理前端)
- 返回某个日期的所有待办事项(管理前端)
关于路由的最佳实践是什么?以下是我想到的几种方案:
-
方案一:使用单一路由
GET /todos两个前端都可以访问它。然后在处理程序中,我可以使用if语句来检查当前用户是普通用户还是管理员。如果是普通用户,我返回其待办事项;如果是管理员,我可以通过过滤器,根据提供的project_id、user_id或date_id返回某个项目、某个用户或某个日期下的所有待办事项。 -
方案二:使用多个路由,例如:
GET /todos(针对用户,返回我的待办事项)GET /projects/:project_id/todos(针对管理员,返回ID为:project_id的项目下的待办事项)GET /dates/:date_id/todos(针对管理员,返回ID为:date_id的日期下的待办事项)GET /users/:user_id/todos(针对管理员,返回ID为:user_id的用户的所有待办事项)
如果我选择第二种方案(多个路由),那么我会发现第一个路由仅由用户访问,而后三个路由仅由管理员访问。那么,我是否应该像这样分组我的管理路由:
- 管理路由组
GET /admin/projects/:project_id/todosGET /admin/dates/:date_id/todosGET /admin/users/:user_id/todos
使用单一的 GET /todos 路由,意味着我所有的处理程序方法都需要检查当前用户是普通用户还是管理员,并返回相应的数据。如果我选择第二种方案,我可以为后三个路由添加一个管理员中间件,从而避免在所有处理程序中使用 if admin 语句。
那么,我应该只有一个 todos_handler.go 文件,还是也应该有一个 todos_admin_handler.go 文件来分离代码?我觉得这样会让事情更清晰,但可能会导致代码重复。
我知道所有方案都可行,但我只是想了解推荐的做法和建议是什么。
谢谢!
更多关于Golang后端路由如何同时服务两个前端应用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang后端路由如何同时服务两个前端应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理多前端应用的后端路由,推荐采用方案二并结合路由分组的方式。这样可以实现清晰的权限分离和代码组织。以下是具体实现示例:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 中间件:检查管理员权限
func AdminMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 这里实现实际的管理员验证逻辑
// 例如:检查JWT令牌、会话等
isAdmin := c.GetHeader("X-User-Role") == "admin"
if !isAdmin {
c.JSON(http.StatusForbidden, gin.H{"error": "管理员权限不足"})
c.Abort()
return
}
c.Next()
}
}
// 中间件:检查用户权限
func UserMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 这里实现实际的用户验证逻辑
userID := c.GetHeader("X-User-ID")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})
c.Abort()
return
}
c.Set("userID", userID)
c.Next()
}
}
// 用户端处理器
type UserTodoHandler struct{}
func (h *UserTodoHandler) GetTodos(c *gin.Context) {
userID := c.GetString("userID")
// 根据userID获取用户的待办事项
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"todos": []string{"用户待办事项1", "用户待办事项2"},
})
}
// 管理端处理器
type AdminTodoHandler struct{}
func (h *AdminTodoHandler) GetUserTodos(c *gin.Context) {
userID := c.Param("user_id")
// 获取指定用户的所有待办事项
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"todos": []string{"管理员查看用户待办事项"},
})
}
func (h *AdminTodoHandler) GetProjectTodos(c *gin.Context) {
projectID := c.Param("project_id")
// 获取指定项目的所有待办事项
c.JSON(http.StatusOK, gin.H{
"project_id": projectID,
"todos": []string{"项目待办事项1", "项目待办事项2"},
})
}
func (h *AdminTodoHandler) GetDateTodos(c *gin.Context) {
dateID := c.Param("date_id")
// 获取指定日期的所有待办事项
c.JSON(http.StatusOK, gin.H{
"date_id": dateID,
"todos": []string{"日期待办事项1", "日期待办事项2"},
})
}
func main() {
r := gin.Default()
userHandler := &UserTodoHandler{}
adminHandler := &AdminTodoHandler{}
// 用户路由组
userGroup := r.Group("/api")
userGroup.Use(UserMiddleware())
{
userGroup.GET("/todos", userHandler.GetTodos)
}
// 管理路由组
adminGroup := r.Group("/api/admin")
adminGroup.Use(AdminMiddleware())
{
adminGroup.GET("/users/:user_id/todos", adminHandler.GetUserTodos)
adminGroup.GET("/projects/:project_id/todos", adminHandler.GetProjectTodos)
adminGroup.GET("/dates/:date_id/todos", adminHandler.GetDateTodos)
}
r.Run(":8080")
}
文件结构建议:
handlers/
├── todos/
│ ├── user_handler.go # 用户端处理器
│ └── admin_handler.go # 管理端处理器
middleware/
├── auth.go # 认证中间件
├── admin.go # 管理员中间件
└── user.go # 用户中间件
routes/
├── user_routes.go # 用户路由注册
└── admin_routes.go # 管理路由注册
main.go # 主程序入口
这种架构的优势:
- 权限分离清晰:通过中间件在路由层进行权限控制,避免在每个处理器中重复检查
- API设计RESTful:路由路径明确表达资源关系
- 代码组织良好:不同角色的处理器分离,便于维护和扩展
- 安全性更好:管理员路由有独立的中间件保护
- 可扩展性强:新增前端应用时只需添加新的路由组和中间件
路由示例:
- 用户端:
GET /api/todos - 管理端:
GET /api/admin/users/123/todos - 管理端:
GET /api/admin/projects/456/todos - 管理端:
GET /api/admin/dates/2024-01-01/todos
这种方案避免了在单个处理器中使用复杂的条件判断,使代码更易于测试和维护。

