You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:15:50