如何在Gin中除了一个路由外,从所有路由中提供静态文件?

huangapple go评论68阅读模式
英文:

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")
}

huangapple
  • 本文由 发表于 2021年9月10日 04:05:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/69124160.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定