我想让我的应用程序服务于以下事物。
我做了如下代码:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.Static("/", "/www")
apiv1 := r.Group("api/v1")
{
apiv1.GET("/disk", diskSpaceHandler)
apiv1.GET("/memory", memoryHandler)
apiv1.GET("/cpu", cpuHandler)
}
r.Run(":80")
}
Run Code Online (Sandbox Code Playgroud)
当我运行代码时,它恐慌:
panic: path segment '/api/v1/disk' conflicts with existing wildcard '/*filepath' in path '/api/v1/disk'
Run Code Online (Sandbox Code Playgroud)
我明白为什么它会恐慌,但我不知道如何解决。
我脑子里只有两件事:
先感谢您。
bla*_*een 21
这是Gin 底层路由器实现的预期功能。路由在前缀上进行匹配,因此与另一个现有路径段处于同一位置的任何路径参数或通配符都会导致冲突。
在这个特定的问答中,该方法RouterGroup.Static将通配符添加/*filepath到您提供服务的路由中。如果该路由是根路由/,则通配符将与您声明的所有其他路由发生冲突。
您必须承认没有直接的解决方案,因为这就是 Gin 的路由器实现的工作原理。如果您不能接受解决方法,那么您可能必须更改 HTTP 框架。评论中提到 Echo 作为替代方案。
1. 如果您可以更改路线映射
最好的解决方法不是没有解决方法,而是拥抱 Gin 的设计。然后你可以简单地在静态文件路径中添加一个唯一的前缀:r.Static("/static", "/www")。这并不意味着您更改本地目录结构,仅更改映射到它的路径前缀。请求 URL 必须更改。
2. 通配符与一条或几条其他路由冲突
假设您的路由器只有这两条路由:
/*any
/api/foo
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您可能会使用中间处理程序并手动检查路径参数:
r.GET("/*any", func(c *gin.Context) {
path := c.Param("any")
if strings.HasPrefix(path, "/api") {
apiHandler(c) // your regular api handler
} else {
// handle *any
}
})
Run Code Online (Sandbox Code Playgroud)
3. 与许多其他路由的通配符冲突
哪一种最好取决于您的具体情况和目录结构。
3.1 使用r.NoRoute处理程序;这可能有效,但是是一个糟糕的黑客行为。
r.NoRoute(gin.WrapH(http.FileServer(gin.Dir("static", false))))
r.GET("/api", apiHandler)
Run Code Online (Sandbox Code Playgroud)
static这将从(或任何其他目录)提供文件,但它也会尝试为该组下的所有不存在的路由提供资产/api。例如/api/xyz将由处理程序处理NoRoute。这可能是可以接受的,直到不能接受为止。例如,如果您恰好有一个api在静态资产中命名的文件夹。
3.2 使用中间件;
例如,您还可以找到gin-contrib/static:
// declare before other routes
r.Use(static.Serve("/", static.LocalFile("www", false)))
Run Code Online (Sandbox Code Playgroud)
这个中间件稍微复杂一些,但它也有同样的限制。即:
Engine#RedirectTrailingSlash = false)gin-contrib/static的,如下所示) r := gin.New()
r.Use(func(c *gin.Context) {
fname := "static" + c.Request.URL.Path
if _, err := os.Stat(fname); err == nil {
c.File(fname)
c.Abort() // file found, stop the handler chain
}
// else move on to the next handler in chain
})
r.GET("/api", apiHandler)
r.Run(":5555")
Run Code Online (Sandbox Code Playgroud)
3.3 使用Gin子引擎;如果您有很多潜在的冲突,例如通配符/和带有组的复杂 API 路由等等,这可能是一个不错的选择。使用子引擎可以让你更好地控制它,但实现仍然感觉很麻烦。基于的示例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")
}
Run Code Online (Sandbox Code Playgroud)
如果可以的话,重新设计你的路线。如果你不能,这个答案提供了三种可能的解决方法,但复杂性不断增加。与往常一样,这些限制可能适用也可能不适用于您的特定用例。YMMV。
如果这些都不适合您,也许可以留下评论来指出您的用例。
小智 -3
您应该使用静态中间件,请参阅其示例:
https://github.com/gin-contrib/static#canonical-example
r.Use(static.Serve("/", static.LocalFile("/tmp", false)))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3784 次 |
| 最近记录: |