【问题标题】:How to serve static files from all routes except one in Gin?如何从除 Gin 中的一个路由之外的所有路由提供静态文件?
【发布时间】:2021-11-06 11:20:24
【问题描述】:

正如标题所说,考虑一个 Gin 路由器,我想在其中提供来自所有路由除了一个的静态文件。假设这条路线是/api。第一次尝试可能如下所示:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.StaticFS("/", gin.Dir("static", false))
    r.GET("/api/v1/foo", func(c *gin.Context) { c.JSON(200, gin.H{"foo": true}) })

    r.Run(":9955")
}

底层的RouterGroup.StaticFS(和Static)使用通配符路径参数连接相对路径:path.Join(relativePath, "/*filepath")。当relativePath 是根路径/ 时,它会恐慌:

恐慌:新路径“/api/v1/foo”中的“/api/v1/foo”与现有前缀“/*filepath”中的现有通配符“/*filepath”冲突

这是由于 Gin 的 http 路由器实现:路由匹配 路径前缀,因此 root 上的通配符将与所有其他路由冲突。可以在here 找到有关此行为的更多详细信息——这是提出此问题的地方。

另一种可能的解决方案是给静态文件路由加前缀,这样就不会和/api冲突:

r.StaticFS("/static", gin.Dir("static", false))

但这也不允许我从根目录提供资产。我怎样才能在根目录上使用通配符或等效项,并且仍然匹配一个特定路径?

【问题讨论】:

    标签: go go-gin


    【解决方案1】:

    一种解决方案是在 root 上仅设置一个通配符路径参数,并使用顶级处理程序来检查路径。根据路径前缀,您使用Engine.HandleContext 将上下文重新输入到第二个路由器:

    func main() {
        apiEngine := gin.New()
        apiG := apiEngine.Group("/api")
        {
            apiG.GET("/foo", func(c *gin.Context) { c.JSON(200, gin.H{"foo": true})})
            apiG.GET("/bar", func(c *gin.Context) { c.JSON(200, gin.H{"bar": true})})
        }
    
        r := gin.New()
        r.GET("/*any", func(c *gin.Context) {
            path := c.Param("any")
            if strings.HasPrefix(path, "/api") {
                apiEngine.HandleContext(c)
            } else {
                assetHandler(c)
            }
        })
        r.Run(":9955")
    }
    

    在此示例中,辅助引擎apiEngine 仅用于以通常的方式声明路由,例如组和方法处理程序。你不要运行它。相反,在检查主通配符处理程序上的路径前缀后,您将 Gin 上下文传递到其HandleContext

    在这个例子中,所有的方法都是GET。资产通常使用 GET 服务,但如果您需要在辅助引擎中处理更多 http 方法,请将主处理程序声明为 Any。比如:

        r := gin.New()
        // allows any http method
        r.Any("/*any", func(c *gin.Context) {
            path := c.Param("any")
            if strings.HasPrefix(path, "/api") {
                apiEngine.HandleContext(c) // on this you can declare POST, PUT, etc. 
    
            // sanity check
            } else if c.Request.Method == http.MethodGet {
                assetHandler(c)
            }
        })
        r.Run(":9955")
    

    【讨论】:

    • 你不能使用 404 处理程序来为除 n apiengine 定义的路径之外的所有其他路径提供静态资产吗?
    • @mh-cbon 该技巧还将为所有以/api 前缀开头的非现有路由提供资产
    猜你喜欢
    • 2017-07-27
    • 1970-01-01
    • 2019-12-12
    • 2016-12-16
    • 2017-08-16
    • 1970-01-01
    • 2019-05-07
    • 2016-07-22
    • 2020-08-03
    相关资源
    最近更新 更多