如何为Gin框架所有请求检查User Agent并实现路由拦截?
问题描述
我已经定义了如下getUserAgent函数,用来解析请求的User Agent并判断是否为爬虫Bot:
func getUserAgent(c *gin.Context) bool { ua := ua.Parse(c.Request.UserAgent()) if ua.Bot { return false } else { return true } }
同时我有以下Gin路由配置:
func Routes(router *gin.Engine) { router.GET("/user_agent", getUserAgent) router.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) router.GET("/:some_urls", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) categories := router.Group("/categories") { categories.GET("/", controller.GetAllCategories) } router.GET("/category_detail", controller.GetCategoriesById) products := router.Group("/products") { products.GET("/", controller.GetAllProducts_by_multi_params) } ...
我需要在每个路由中调用getUserAgent函数,若返回true则执行正常路由逻辑,若返回false则返回其他内容,该怎么实现?
解决方案
最简洁高效的方式是把getUserAgent改造成Gin中间件,这样可以全局或批量应用到所有路由/路由组,避免在每个路由里重复编写判断逻辑。
1. 将函数改造为中间件
调整原函数,使其符合Gin中间件的规范:
func BotCheckMiddleware() gin.HandlerFunc { return func(c *gin.Context) { ua := ua.Parse(c.Request.UserAgent()) // 检测到爬虫Bot时,返回自定义内容并终止后续逻辑 if ua.Bot { // 可根据需求替换为JSON、HTML等格式 c.String(http.StatusForbidden, "禁止爬虫访问") c.Abort() // 中断请求链,不执行后续路由处理 return } // 非爬虫请求,继续执行后续路由逻辑 c.Next() } }
2. 应用中间件
根据需求选择以下任意一种方式应用中间件:
方式一:全局应用到所有路由
如果所有路由都需要爬虫检测,直接在引擎上注册中间件:
func Routes(router *gin.Engine) { // 全局注册爬虫检测中间件,所有路由自动生效 router.Use(BotCheckMiddleware()) router.GET("/user_agent", func(c *gin.Context) { ua := ua.Parse(c.Request.UserAgent()) c.JSON(http.StatusOK, gin.H{"is_bot": ua.Bot}) }) router.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) router.GET("/:some_urls", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) categories := router.Group("/categories") { categories.GET("/", controller.GetAllCategories) } router.GET("/category_detail", controller.GetCategoriesById) products := router.Group("/products") { products.GET("/", controller.GetAllProducts_by_multi_params) } // ...其他路由 }
方式二:针对特定路由组应用
如果仅部分路由组需要检测,可在组定义时添加中间件:
func Routes(router *gin.Engine) { // 无需检测的路由直接定义 router.GET("/user_agent", func(c *gin.Context) { ua := ua.Parse(c.Request.UserAgent()) c.JSON(http.StatusOK, gin.H{"is_bot": ua.Bot}) }) router.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) router.GET("/:some_urls", func(c *gin.Context) { c.HTML(http.StatusOK, "index.html", nil) }) // 给categories组添加爬虫检测 categories := router.Group("/categories", BotCheckMiddleware()) { categories.GET("/", controller.GetAllCategories) } // 给单个路由添加检测 router.GET("/category_detail", BotCheckMiddleware(), controller.GetCategoriesById) // 给products组添加检测 products := router.Group("/products", BotCheckMiddleware()) { products.GET("/", controller.GetAllProducts_by_multi_params) } // ...其他路由 }
方式三:给单个路由单独添加
如果仅个别路由需要检测,直接在路由定义时附加中间件:
router.GET("/category_detail", BotCheckMiddleware(), controller.GetCategoriesById)
3. 注意事项
c.Abort()会终止后续请求处理逻辑,因此检测到爬虫后不会执行对应的路由函数。- 返回内容可根据业务需求调整,比如替换为
c.JSON返回JSON格式提示,或c.HTML返回自定义页面。 - 原
/user_agent路由若仅用于测试UA检测,可保留但建议调整逻辑,因为全局中间件会优先执行检测。
内容的提问来源于stack exchange,提问作者Casper
相关产品推荐
相关产品推荐

