gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
78.23k stars 7.98k forks source link

Root static resource router not supported #2846

Open LoSunny opened 3 years ago

LoSunny commented 3 years ago

Description

This is a follow up of the issue: https://github.com/gin-gonic/gin/issues/2537

How to reproduce

package route

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

func main() {
    var app = gin.Default()

    api.RunRoot(app.Group("/api"))
    app.StaticFS("/", gin.Dir("dist", false))
    app.Run(":8080")
}

Expectations

If the URL starts with the `/api`, then it is handled by the other router, else it searches the file in the `StaticFS`

Actual result

An error occur:
[GIN-debug] GET    /*filepath                --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
[GIN-debug] HEAD   /*filepath                --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
[GIN-debug] GET    /api/ping                 --> SunnyMovie/server/route/routes/api.RunRoot.func1 (4 handlers)
panic: '/api/ping' in new path '/api/ping' conflicts with existing wildcard '/*filepath' in existing prefix '/*filepath'

Environment

automano commented 3 years ago

your code snip is not runnable with the error "undeclared name: api"

LoSunny commented 3 years ago

Sorry, this should work

package route

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

func main() {
    var app = gin.Default()

    app.Group("/api").GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    app.StaticFS("/", gin.Dir("dist", false))
    app.Run(":8080")
}
automano commented 3 years ago

Basically, you can't use gin like this and the panic error message already describes your problem. This problem occurs mainly because many golang frameworks use httprouter as their routing module. httprouter uses explicit matching for performance optimization, which causes many wildcards to conflict with specific routes.

app.StaticFS("/", gin.Dir("dist", false)) will register the wildcard /*filename as the router path but this is already occupied by /api app.Group("/api")

I recommend you don't use the root path to serve your static files.

you may find some other similar issues like #1301

LoSunny commented 3 years ago

But according to https://github.com/gin-gonic/gin/pull/2663 , this issue should be been solved

automano commented 3 years ago

Did a careful read and noticed this "This only works for param wildcards of the form :name and doesn't change the existing * " Maybe this is why in your situation there is still conflict error.

image