【新手】关于go框架gin的静态托管和api同时使用报错的问题

gin框架,我想使用/,在打开网站的时候返回静态首页,使用其他比如/hello的时候返回接口,我是新鸟啊,开发的时候遇到了问题,求解大家,谢谢

图片描述

如代码截图和注释,使用了静态/就不能用接口了,我百度了很久找不到原因

package main

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

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

    // 单独使用下面的静态托管能在http://localhost:2019/看到正确的html
    router.Static("/", "./www")
    
    // 但是下面的接口就不能使用了,必须注释掉上面一句,下面接口才能使用
    router.GET("/hello", func(c *gin.Context) {
        c.String(200, `hello golang.`)
    })
    router.Run(":2019")
}

错误信息

图片描述

求教,谢谢

阅读 7.6k
3 个回答

router.Static("/", "./www") 其中的/相当于/*,包含了/hello
建议为静态页面加个子目录如/web/

你可以理解为,这是 gin 中的限制,gin 中每个路由的规则是不能有交集的,比如这里的 //web 是有交集的,即 /web 也满足是 / 的情况。可以看看一个 github issue 中的关于问题的这个描述。

那这个问题该怎么解决呢?

我想到的是,静态页面 / 修改为 /static。如果是某些特殊的效果,可以在 nginx 反向代理之上做一层转化,将所有 / 指向 /static,nginx 的 location 规则还是比较丰富的。

说实话,我也不知道 gin 为什么这么做?或许是为了降低复杂度,降低出错的可能吧。通常,在用其他的 web 框架时,都是会根据 router 设置优先级的顺序决定启动那个路由。

结论: 两条路由注册的顺序换一下就好了

原理: httprouter存在注册路由优先级问题,/*路由会包含后续注册的一切的路由,导致后续全部失效,而不存在优先级 常量>遍历>通配符的匹配效果,实际谁先注册谁优先级高,而gin就继承了httprouter的整个问题

源码urlPattern := path.Join(relativePath, "/*filepath"),join了路径,实践static注册路径为/*filepath.

// Static serves files from the given file system root.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use :
//     router.Static("/static", "/var/www")
func (group *RouterGroup) Static(relativePath, root string) IRoutes {
    return group.StaticFS(relativePath, Dir(root, false))
}

// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
// Gin by default user: gin.Dir()
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
    if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
        panic("URL parameters can not be used when serving a static folder")
    }
    handler := group.createStaticHandler(relativePath, fs)
    urlPattern := path.Join(relativePath, "/*filepath")

    // Register GET and HEAD handlers
    group.GET(urlPattern, handler)
    group.HEAD(urlPattern, handler)
    return group.returnObj()
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏