中国空间站什么时候建成,城市生活网官方网站app,wordpress in,出国游做的好的网站Gin 是 Golang 生态中目前最受用户欢迎和关注的 Web 框架#xff0c;但是生态中的 Static 中间件使用起来却一直很不顺手。
所以#xff0c;我顺手改了它#xff0c;然后把这个改良版开源了。
写在前面 Gin-static 的改良版#xff0c;我开源在了 soulteary/gin-static但是生态中的 Static 中间件使用起来却一直很不顺手。
所以我顺手改了它然后把这个改良版开源了。
写在前面 Gin-static 的改良版我开源在了 soulteary/gin-static也发布在了 Go 软件包市场pkg.go.dev/github.com/soulteary/gin-static有需要可以自取。
提到改良优化那么就不得不提 Go-Gin 和原版的 Gin-Static 对于静态文件的处理。
关于 Go-Gin 和 Gin 社区的静态文件处理
在 Gin 的官方文档中关于如何使用 Gin 来处理“静态文件相关请求” 写的很清楚
func main() {router : gin.Default()router.Static(/assets, ./assets)router.StaticFS(/more_static, http.Dir(my_file_system))router.StaticFile(/favicon.ico, ./resources/favicon.ico)// Listen and serve on 0.0.0.0:8080router.Run(:8080)
}不过这个例子中官方只考虑到了静态资源都存放于二级目录并且静态资源目录只存在静态资源的情况。
如果我们的静态资源需要使用 / 根目录或者在静态目录所在的 /assets/* 中存在需要 Golang后端程序要进行处理的“动态逻辑”或者我们希望使用通配符来处理某些静态文件路由这个玩法就失效了。而这个情况在很多前端比较重的应用中非常常见尤其是我们希望用 Golang 来优化 Node 或者纯前端实现的项目时。
这个问题在社区的反馈中有提到过“#21不能够在 / 根目录使用静态文件”、“#360通配符和静态文件冲突”。
所以在八年前 gin-contrib 社区出现了一个专注于处理静态程序的中间件gin-contrib/static 帮助我们解决了这个问题使用的方法也很简单
package mainimport (github.com/gin-contrib/staticgithub.com/gin-gonic/gin
)func main() {r : gin.Default()// ...r.Use(static.Serve(/, static.LocalFile(/tmp, false)))// ...
}不过当基础功能完备后这个插件就陷入了沉睡状态版本号停留在 0.0.1 直至现在。
时过境迁Golang 的版本已经升到了 1.21这个中间件中引用的一些软件也变的陈旧甚至被废弃社区中也挂起了一些很好的功能实现比如“#19Go 原生文件嵌入实现”但是因为作者比较忙碌或者没有相同的痛点所以 PR 一直未能合并。
在若干年后批判古早的代码毫无意义所以我们就不扯出代码一行行审阅了我个人认为相对靠谱的动作是帮助它解决问题。
在早些时候《深入浅出 Golang 资源嵌入方案前篇》、《深入浅出 Golang 资源嵌入方案go-bindata篇》这两篇文章中我提到过的 Golang 官方和社区排名靠前的资源嵌入方案对于制作性能靠谱、方便分发的单文件应用非常有价值。
所以结合社区里存在的 PR 提交feat: Implement embed folder and a better organisation我提交了一个新的 PR#46对之前的程序和 PR 实现的代码都做了一些完善并且确保这个中间件测试覆盖率是 100%使用起来能够更安心。
下载 gin-static 优化版
和其他社区软件一样使用下面的一句话命令可以完成 gin-static 的下载了
go get github.com/soulteary/gin-static如果你是全新使用在你的在程序中添加下面的引用内容即可
import github.com/soulteary/gin-static// 或
import (static github.com/soulteary/gin-static
)如果你已经使用了社区的 github.com/gin-gonic/gin-static 软件包并且不想修改已有程序的引用和行为那么我们可以用另外一种方法。
在你的 go.mod 文件中我们应该能够看到类似下面的内容
module your-projectgo 1.21.2require (github.com/gin-gonic/gin v1.9.1github.com/gin-gonic/gin-static v0.0.1
)我们只需要在 require 之前添加一条依赖替换规则即可
module your-projectgo 1.21.2replace (github.com/gin-gonic/gin-static v0.0.1 github.com/soulteary/gin-static v0.0.5
)require (github.com/gin-gonic/gin v1.9.1github.com/gin-gonic/gin-static v0.0.1
)完成内容添加后我们执行 go mod tidy完成依赖的更新即可。不论是哪一种使用方式当你执行完命令后我们就能够使用支持 Go 原生嵌入文件使用啦。
使用 gin-static 优化版
在项目的示例目录中我提交了两个使用示例程序分别包含“基础使用simple” 和 支持“文件嵌入”的例子embed
├── embed
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── public
│ └── page
└── simple├── go.mod├── go.sum├── main.go└── public└── index.html基础使用
程序的基础使用和之前社区版本的接口一致如果我们想在程序中直接使用本地的静态文件
package mainimport (loggithub.com/gin-gonic/ginstatic github.com/soulteary/gin-static
)func main() {r : gin.Default()// 静态文件在默认根路径r.Use(static.Serve(/, static.LocalFile(./public, false)))// 其他路径 /other-place// r.Use(static.Serve(/other-place, static.LocalFile(./public, false)))r.GET(/ping, func(c *gin.Context) {c.String(200, test)})// Listen and Server in 0.0.0.0:8080if err : r.Run(:8080); err ! nil {log.Fatal(err)}
}实际使用过程中我们还可以对根目录做一些额外的逻辑使用 r.[Method] 来覆盖默认的静态文件路由
// 将静态资源注册到根目录使用本地的 Public 作为“数据源”
r.Use(static.Serve(/, static.LocalFile(public, false)))
// 允许添加其他的路由规则处理根目录
r.GET(/, func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, /somewhere)
})文件嵌入
在早些时候《深入浅出 Golang 资源嵌入方案前篇》、《深入浅出 Golang 资源嵌入方案go-bindata篇》这两篇文章中我提到过的 Golang 官方和社区排名靠前的资源嵌入方案对于制作性能靠谱、方便分发的单文件应用非常有价值。
使用 gin-static 来处理嵌入文件非常简单并且支持多种用法
package mainimport (embedfmtnet/httpgithub.com/gin-gonic/gin
)//go:embed public
var EmbedFS embed.FSfunc main() {r : gin.Default()// Method 1: use as Gin Router// trim embedfs path public/page, and use it as url path /r.GET(/, static.ServeEmbed(public/page, EmbedFS))// OR, Method 2: use as middleware// trim embedfs path public/page, the embedfs path start with /r.Use(static.ServeEmbed(public/page, EmbedFS))// OR, Method 2.1: use as middleware// trim embedfs path public/page, the embedfs path start with /public/pager.Use(static.ServeEmbed(, EmbedFS))// OR, Method 3: use as manual// trim embedfs path public/page, the embedfs path start with /public/page// staticFiles, err : static.EmbedFolder(EmbedFS, public/page)// if err ! nil {// log.Fatalln(initialization of embed folder failed:, err)// } else {// r.Use(static.Serve(/, staticFiles))// }r.GET(/ping, func(c *gin.Context) {c.String(200, test)})r.NoRoute(func(c *gin.Context) {fmt.Printf(%s doesnt exists, redirect on /\n, c.Request.URL.Path)c.Redirect(http.StatusMovedPermanently, /)})// Listen and Server in 0.0.0.0:8080r.Run(:8080)
}
上面的代码中我们首先使用 //go:embed public 将本地的 public 目录读入 Golang 程序中转换为程序可以访问的对象。然后你就可以根据你自己的具体情况使用上面程序中的任意一种用法了。
当我们使用 go build 构建程序后就能够得到一个包含了所有依赖静态文件的单一可执行文件啦。
个人倾向用法
我个人在使用的过程中倾向于将上面两种用法合并在一起当我们在开发的时候使用本地文件系统前者而当我们构建的时候则使用 Go 内嵌文件系统后者。
这样可以确保我们在玩的时候静态文件支持所见即所得的修改立即生效下面是我个人喜欢的用法示例
if debugMode {r.Use(static.Serve(/, static.LocalFile(public, false)))
} else {r.NoRoute(// 例如对存在的具体目录进行一些特殊逻辑处理func(c *gin.Context) {if c.Request.URL.Path /somewhere/ {c.Data(http.StatusOK, text/html; charsetutf-8, []byte(custom as you like))c.Abort()}},static.ServeEmbed(public, EmbedFS),)// 或者不需要额外处理和拦截存在的静态文件// r.NoRoute(static.ServeEmbed(public, EmbedFS))
}在上面的代码里我们将本地的静态文件在开发时默认挂载在 / 根目录用于“兜底访问fallback”这些文件允许被各种其他的路由覆盖。当我们进行构建或设置 debugModefalse 的时候我们将静态文件挂载低优先级的 NoRoute 路由中用于“兜底访问fallback”如果我们需要调整或覆盖一些真实存在的静态文件那么我们需要在路由前做额外的处理。
最后
好了这个中间件就是这么简单我们已经聊完了 80% 相关的内容啦。有机会我们在聊聊更有趣的 Embed 文件优化的故事。
–EOF 本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议欢迎转载、或重新修改使用但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2024年01月03日 统计字数: 6357字 阅读时间: 13分钟阅读 本文链接: https://soulteary.com/2024/01/03/golang-gin-static-middleware-improves.html