问题现象
- fly项目是前后端分离的架构,
- 今天在添加了/api/v1/setting接口后,打开前端页面,随机首页的登陆页就一直不停的刷新;
- 不断请求后端的api接口,后端代码打印日志,也发现,确实在不断响应前端的请求,且状态码是200
排查过程
-
最先:以为是前端问题,修改axios库的请求重试次数,不行;
-
然后:以为是前端代码不知道哪里改了,重新build全新的前端代码,不行;
-
然后:调试后端代码,也发现不了问题;决定先略过
-
最后:无意中,在看后端代码时,发现/api/v1/setting接口的handler注册的位置不对,如下:
- 发现/api/v1/settging 是在需要auth鉴权的分组里注册的;
- 第一反应:我RegSysSettingRouter函数里,没有Use()使用auth相关的中间件,注册哪里无所谓吧
- 然后:发现RegBaseRouter里,对v1使用了中间件
v1Auth := v1.Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()),而v1是指针类型,等于RegBaseRouter和RegSysSettingRouter其实是操作的同一个*gin.RouterGroup实例,且RegSysSettingRouter后执行,那么RegBaseRouter里注册的中间件,自然在/api/v1/setting路由处也要被使用,而请求该路由是在login登陆行为之前,此时请求还没有有效的token,自然就在中间件中被unauthorizator()函数给响应了,且该函数原本填充的是200状态码,之后:前端(不知原因)接到这样的响应,就会不断重试该接口,
一开始:写的位置
func regAuthCheckRouter(r *gin.Engine, jwtMiddleware *jwt.GinJWTMiddleware) {
// 先从这里写,核心业务逻辑先写
r.POST("/login", jwtMiddleware.LoginHandler)
r.GET("refresh_token", jwtMiddleware.RefreshHandler)
// ws相关的
// r.Group("").Use(authMiddleware.MiddlewareFunc()).GET("/ws/:id/:channel", ws.WebsocketManager.WsClient)
// r.Group("").Use(authMiddleware.MiddlewareFunc()).GET("/wslogout/:id/:channel", ws.WebsocketManager.UnWsClient)
v1 := r.Group("/api/v1")
// admin相关
// adminRouter.RegPageRouter(v1, jwtMiddleware)
adminRouter.RegBaseRouter(v1, jwtMiddleware)
adminRouter.RegSysSettingRouter(v1) # 这里!
// cmdb相关
}
应该写的位置:(在不需要鉴权的地方注册)
func regNoAuthCheckRouter(r *gin.Engine) {
// 不需要鉴权的路由api
g := r.Group("/api/v1")
// 服务运行所在服务的信息
g.GET("/monitor/server", monitor.ServerInfo)
g.GET("/getCaptcha", system.GenCaptchaHandler)
adminRouter.RegSysSettingRouter(g) // /api/v1/settting相关的路由
}
收获-改进:
- Unauthorized()这个函数写的不好,未鉴权的时候,不应该状态码回200 ,改进:(改进后,经测试, 即便该路由注册,放错位置,前端也不会无限重试)(猜测:该行为,可能跟响应码为200,但数据却获取不到有关?)
func Unauthorized(c *gin.Context, code int, message string) {
c.JSON(http.StatusUnauthorized, gin.H{
"code": code,
"msg": message,
})
}
v1 := r.Group("/api/v1") v2 := r.Group("/api/v1")其中的v1和v2是两个不同的*gin.RouterGroup实例,是可以,也应该是 具有不同的中间件,只是前缀相同- 排查思路:控制变量,既然是添加了 /api/v1/setting路由之后出现的问题,那么应该第一反应应该是,也该是从这个接口的相关后端代码查起!