有关 gin.Context.FileFromFS 的小坑

205 天前
 zzhirong

以下是有问题的实验代码。

package main

/*  当前目录
.
├── go.mod
├── go.sum
├── dist
│   └── index.html
├── main.go
*/

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

//go:embed dist
var fs embed.FS

func main() {
	router := gin.Default()
	router.GET("/", func(c *gin.Context){
		c.FileFromFS("dist/index.html", http.FS(fs))
	})
	router.Run(":8080")
}

执行

go run . &
wget http://localhost:8080

大家猜一下结果是什么?

2094 次点击
所在节点    Go 编程语言
11 条回复
zzhirong
205 天前
补充一点:帖子被贴上 “404 not found” 的标签了,应该是没有创建 ./dist/index.html 文件的缘故,但这里说的问题并不是这个低级错误。

- wget http://localhost:8080 返回的是 301 ,而且我这边返回的是 20 次 301 (超过阀值强行退出)。
tbxark
205 天前
试一下 sf, err := fs.Sub(fs, "dist")
zzhirong
205 天前
@tbxark 原因我昨天通过调试就已经知道了,就是先把问题代码贴上来,看看大家能否一眼就能看出,你提出的修改方案也还是会返回 301

// 还是会返回 301
dist, _ := fs.Sub(dist, "dist")
router.GET("/", func(c *gin.Context){
c.FileFromFS("index.html", http.FS(dist))
})
lovelylain
205 天前
HandleContext 内部转发
zzhirong
205 天前
@lovelylain 什么意思?你的意思是 /dist/index.html 会内部转发到 / 么?但是,wget 确实收到了 301 ,然后一直有尝试重定向,然后一直收到 301 。
kingcanfish
204 天前
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 设置静态文件服务
r.Static("/dist", "./dist")
// 根路径重定向到 /dist/index.html
r.GET("/", func(c *gin.Context) {
c.Redirect( http.StatusMovedPermanently, "/dist/index.html")
})
// 启动服务器
r.Run(":8080") // 默认监听 0.0.0.0:8080
}
这样呗
你这样的用法确实感觉有点奇怪 ,属于是标准库没有想到用人会这么用 gin 也没想到有人会这么用
zzhirong
204 天前
@kingcanfish 你的方案会有两个 301 重定向,当你碰到首页不在根目录下的情况,你的最佳实践是什么,我目前的做法是

r.GET("/", func(c *gin.Context) {
c.File("dist/") // 会直接返回 dist/index.html ,没有重定向
})

把 / 映射到 index.html 应该很常见吧,有更好的方式么?
kingcanfish
204 天前
@zzhirong #7 最佳实践就是用 nginx 做🤣, gin 只用来跑 api
gvison
204 天前
我是这样使用 gin 来做文件服务器获取 index.html ,访问 url 要求包括 go:embed 的目录 dist ,例如 wget http://localhost:8080/dist/index.html

```go
package main

import (
"embed"
"github.com/gin-gonic/gin"
"github.com/go-dev-frame/sponge/pkg/gin/frontend"
)

//go:embed dist
var staticFS embed.FS

func main() {
r := gin.Default()
f := frontend.New("dist",
frontend.WithEmbedFS(staticFS),
frontend.With404ToHome(),
)
err := f.SetRouter(r)
if err != nil {
panic(err)
}
err = r.Run(":8080")
panic(err)
}
```
zzhirong
204 天前
@gvison 你的方案确实可以,但我不想引入额外的包而且我就想把主页挂在 / 下,有无办法只用 gin 实现?
zzhirong
204 天前
@gvison 看了下引用的 frontend 包的源码,发现 github.com/go-dev-frame/sponge/pkg/gin/frontend.FrontEnd.setEmbedFSRouter 有个新的实现方式

staticFS, _ := fs.Sub(staticFS, "dist")
r.GET("/*file", func(c *gin.Context){
staticServer := http.FileServer( http.FS(staticFS))
staticServer.ServeHTTP(c.Writer, c.Request)
})

这种方案也是可以的,直接 wget http://localhost:8080/ 这会返回 301

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1121924

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX