英文:
How to serve static files from all routes except one in Gin?
问题
如标题所述,考虑一个 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
是根路径 /
时,它会引发 panic:
> panic: '/api/v1/foo' in new path '/api/v1/foo' conflicts with existing wildcard '/*filepath' in existing prefix '/*filepath'
这是由于 Gin 的 HTTP 路由器实现的原因:路由匹配是基于路径前缀的,因此根路径上的通配符将与每个其他路由冲突。关于这种行为的更多细节可以在这里找到,这也是提出这个问题的地方。
另一个可能的解决方案是给静态文件路由添加前缀,以避免与 /api
冲突:
r.StaticFS("/static", gin.Dir("static", false))
但这样做将无法从根路径提供资源。我该如何在根路径上使用通配符或等效的方式,并且仍然匹配一个特定的路径?
英文:
As the title says, consider a Gin router where I want to serve static files from all routes except one. Let's say this one route is /api
. A first attempt might look like this:
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")
}
The RouterGroup.StaticFS
(and Static
too) under the hood joins the relative path with a wildcard path param: path.Join(relativePath, "/*filepath")
. When relativePath
is the root path /
, it will panic with:
> panic: '/api/v1/foo' in new path '/api/v1/foo' conflicts with existing wildcard '/*filepath' in existing prefix '/*filepath'
This is due to Gin's http router implementation: routing matches on the path prefix, so a wildcard on root will conflict with every other route. More details about this behavior can be found here — which is where this question was raised.
Another possible solution is to prefix the static file route, so that it doesn't conflict with /api
:
r.StaticFS("/static", gin.Dir("static", false))
but this doesn't allow me to serve assets from root too. How can I have a wildcard, or equivalent, on root and still match on one specific path?
答案1
得分: 4
有一个名为static的包可以实现这个功能。
https://github.com/gin-contrib/static#canonical-example
只需按照以下方式修改示例代码:
package main
import (
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 服务于名为static的目录
r.Use(static.Serve("/", static.LocalFile("static", false)))
// 其他常规路由
r.GET("/api/ping", func(c *gin.Context) {
c.String(200, "ping")
})
r.Run(":9955")
}
英文:
There is a package called static for this.
https://github.com/gin-contrib/static#canonical-example
just modify the example as follows
package main
import (
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// server a directory called static
r.Use(static.Serve("/", static.LocalFile("static", false)))
// And any route as usual
r.GET("/api/ping", func(c *gin.Context) {
c.String(200, "ping")
})
r.Run(":9955")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论