惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
M
MIT News - Artificial intelligence
S
SegmentFault 最新的问题
博客园 - 叶小钗
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
博客园_首页
U
Unit 42
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

吴润写字的地方

从零构建 A 股 ETF 动量轮动系统:一个量化新手的完整指南 2025 年 8 月 Digest 2025 年 7 月 Digest 2025 年 6 月 Digest 2025 年 5 月 Digest 2025 年 4 月 Digest 清明桐庐行 2025 年 3 月 Digest 2024 年终总结 换车 崇明岛一日游 夜游徐汇滨江绿地 2023 年终总结 踏春之浦康休闲公园 香港澳门行 读「投资第一课」有感 皮皮玩球 Chrome 插件推荐 Go 并发之道:并发介绍 The Night Agent 我是如何使用 ChatGPT 的 2022 年终总结 在 Ubuntu 上搭建 MinIO 2021 年终总结 Golang 不可寻址的理解 Golang 的 defer 关键字使用注意事项 恭王府 强制删除 k8s terminating 状态命名空间 PromQL 计算 CPU 使用率 PromQL 如何计算变化(率)
解决 gin 路由冲突问题
2021-03-19 · via 吴润写字的地方

使用 gin 框架时,如果有两个这样的路由:

  • GET /users/:id
  • GET /users/info

gin 会报错:

panic: 'info' in new path '/users/info' conflicts with existing wildcard ':id' in existing prefix '/users/:id'

原因是这两个路由拥有一致的 HTTP 方法(指 GET/POST/PUT/DELETE 等)和请求路径前缀,且在相同的路由位置上,第一个路由是 wildcard(指 :id 这种形式)参数,第二个路由是普通字符串 info,那么就会发生路由冲突。 发生冲突该如何解决?

router.GET("/users/:id", func(ctx *gin.Context) {
        switch c.Param("id") {
        case "info":
            handlers.getUserInfo(ctx)
        default:
            handlers.GetUser(ctx)
        }
    })

思路是 :id 这个通配结果如果是 info,则拦截下来,走 /users/info 对应的 handler 逻辑;:id 通配结果非 info,则走 /users/:id 对应的 handler 逻辑。虽然不太好看,但能解决问题。

稍微复杂的路由冲突可能是这样的:

  • GET /:channelID/:programID
  • GET /redirect/:channelID/:programID

:channelIDredirect 冲突,并且两个路由的层级是不一样的,第一个有两级,第二个有三级,如何解决?

先将上面的路由转化下:

  • GET /:path1/:path2
  • GET /:path1/:path2/:path3

转换后逻辑更清晰,

  • 如果 path1 = redirect, 且 path2 和 path3 都不为空,则匹配到第二个路由,那么 path2 与 path3 分别是 channelID 和 programID

  • 如果 path1 不为空,且 path1 != redirect, 且 path2 不为空,且 path3 为空,则匹配到第一个路由,那么 path1 与 path2 分别是 channelID 和 programID

router.GET("/:path1/:path2", getHandler)       
router.GET("/:path1/:path2/:path3", getHandler)

func getHandler(ctx *gin.Context) {
    if ctx.Param("path1") == "redirect" {
        if ctx.Param("path2") != "" && ctx.Param("path3") != "" {
            ctx.Params = append(ctx.Params, gin.Param{Key: "channelID", Value: ctx.Param("path2")},
                gin.Param{Key: "programID", Value: ctx.Param("path3")})

            handlers.GetRedirectResult(ctx)
        }
    } else if ctx.Param("path1") != "" && ctx.Param("path2") != "" && ctx.Param("path3") == "" {
        ctx.Params = append(ctx.Params, gin.Param{Key: "channelID", Value: ctx.Param("path1")},
            gin.Param{Key: "programID", Value: ctx.Param("path2")})

        handlers.GetResult(ctx)
    }
}

以上的法方法是不优雅的,当遇到路由冲突的时候,可以考虑路由设计是否合理(比如是否遵循 RESTful API 规范),尽可能的避免路由冲突问题。由于是重构项目,为了保持接口路由不变,才这么处理的。