前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >(6) 静态网站容器化 - 【Gin源码】 使用Gin FS模式无限 301 重定向了?

(6) 静态网站容器化 - 【Gin源码】 使用Gin FS模式无限 301 重定向了?

作者头像
老麦
发布2025-02-12 15:04:45
发布2025-02-12 15:04:45
4100
代码可运行
举报
文章被收录于专栏:Go与云原生Go与云原生
运行总次数:0
代码可运行

(6) 静态网站容器化 - 【Gin源码】 使用Gin FS模式无限 301 重定向了?

原文链接: https://typonotes.com/posts/2025/02/09/gin-static-fs-301-redirect/

为了解决 BrowserRouter 模式下的, History API Fallback 问题。 我们在后端服务器做了一些兼容配置。

  1. (4) 静态前端容器化 - 单页面应用(SAP) History API Fallback - 刷新 404[1]

但是由于 gin 对于 StaticFS()FileFromFS() 两个方法的实现问题, 造成了无限 301 重定向到首页的问题。

今天我们就来跟着 gin 源码一起看看问题出在哪里。

c.File 本地文件

先来回顾 本地目录的中间件 代码怎么实现的。

代码语言:javascript
代码运行次数:0
复制
func HistoryAPIFallback() func(c *gin.Context) {
returnfunc(c *gin.Context) {

  path := c.Request.URL.Path
// 如果是 API 请求,或者是静态资源(JS、CSS、图片),则放行
if strings.HasPrefix(path, "/api/") || strings.Contains(path, ".") {
   c.Next()
   return
  }

// 返回固定内容。
  c.File("dist/index.html")
  c.Abort() // 中断后续流程。
 }
}

这里使用了 gin 封装的 c.File() 方法。

代码语言:javascript
代码运行次数:0
复制
// File writes the specified file into the body stream in an efficient way.
func (c *Context) File(filepath string) {
 http.ServeFile(c.Writer, c.Request, filepath)
}

调用了标准库的 http.ServeFile() 方法, 可以看到在实现的时候, 为 serveFile 设置了 redirect=false (2)。

这也是为什么使用 c.File() 方法没有 301 条转的原因。

c.FileFromFS FS 文件: 问题所在

在 gin 中同样为 FS 读取文件提供了一个方法 c.FileFromFS

代码语言:javascript
代码运行次数:0
复制
// FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.
func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
 defer func(old string) {
  c.Request.URL.Path = old
 }(c.Request.URL.Path)

 c.Request.URL.Path = filepath

 http.FileServer(fs).ServeHTTP(c.Writer, c.Request)
}

其实现方法并不是与 c.File 中一样, 直接使用 serveFile, 而是使用了 ServeHTTP 接口方法。

代码语言:javascript
代码运行次数:0
复制
type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}

对于接口,我们要看的是 实现对象 http.FileServer(fs)

在图中可以看到, ServeHTTP 同样使用了 serveFile, 但是设置了 redirect=true

就是因为这个, 才会在使用 FileFromFS 的时候出现 301 跳转。

解决方法

解决方法也很简单, 不使用 gin 为我们封装 c.FileFromFS 方法。 而是直接使用 原生方法 http.ServeFileFS

代码语言:javascript
代码运行次数:0
复制
// HistoryAPIFallback 用于前端路由的处理 for History of BrowserRouter
func HistoryAPIFallback(fsys fs.FS) func(c *gin.Context) {
returnfunc(c *gin.Context) {

  path := c.Request.URL.Path
// 如果是 API 请求,或者是静态资源(JS、CSS、图片),则放行
if strings.HasPrefix(path, "/api/") || strings.Contains(path, ".") {
   c.Next()
   return
  }

// 解决方法: 使用 http.ServeFileFS 替代 ServeHTTP
  http.ServeFileFS(c.Writer, c.Request, fsys, "index.html")
  c.Abort()
 }
}

为什么会无限跳转呢?

造成无限跳转的原因, 是在实现中间件 HistoryAPIFallback 的判断检查上的疏漏。

没有对跳转后的路径 / 进行判断。 因此每次都命中 c.FileFromFS, 进行跳转。

redirect=true 时怎样实现的? 效果时什么?

条件比较复杂,建议直接看源码。

当访问 http://example.com/ 这样的 目录路径, 默认读取 index.html 作为页面内容。

简单来说 redirect=true 就是针对 index.html 的路径优化, 删除路径中的 index.html, 跳转到 目录路径

代码语言:javascript
代码运行次数:0
复制
http://example.com/index.html -> https://example.com/
http://example.com/dist/index.html -> https://example.com/dist/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 熊猫云原生Go 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (6) 静态网站容器化 - 【Gin源码】 使用Gin FS模式无限 301 重定向了?
    • c.File 本地文件
    • c.FileFromFS FS 文件: 问题所在
    • 解决方法
    • 为什么会无限跳转呢?
    • redirect=true 时怎样实现的? 效果时什么?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档