提前试用将在 Go1.16 中发布的内嵌静态资源功能
大家好 , 我是站长 polarisxu 。
喜欢 Go 语言有很多理由 , 其中有一点“因为编译为一个二进制文件 , 直接运行 , 没有其他依赖 , 使得部署特别容易 。 ”我想是很多人喜欢的 。
然而一个项目 , 很可能会包含一些静态资源文件 , 这样一来 , 一个 Go 二进制文件就不能解决了 , 需要将静态资源文件一起带上 。 于是有了很多第三方解决方案 , 将静态资源文件“嵌入”最终的 Go 二进制文件中 。 最知名的应该是 go-bindata , 此外还有很多其他的:
- github.com/alecthomas/gobundle
- github.com/GeertJohan/go.rice
- github.com/go-playground/statics
- github.com/gobuffalo/packr
- github.com/knadh/stuffbin
- github.com/mjibson/esc
- github.com/omeid/go-resources
- github.com/phogolabs/parcello
- github.com/pyros2097/go-embed
- github.com/rakyll/statik
- github.com/shurcooL/vfsgen
- github.com/UnnoTed/fileb0x
- github.com/wlbr/templify
- perkeep.org/pkg/fileembed
2020 年 10 月 30 日 , Russ Cox 提交了最终的实现:[cmd/go: add //go:embed support](cmd/go: add //go:embed support) , 意味着你在 tip 版本可以试用该功能了 。 Go1.16 版本会包含该功能 。 欢迎大家试用 , 反馈建议 。
01 试用 go embed通过几个示例快速了解 go embed 的用法 。
例 1:内嵌文件 — Web 应用基于 Echo 框架:
package mainimport ( _ "embed" "net/http" "github.com/labstack/echo")//go:embed static/logo.pngvar content []bytefunc main() { e := echo.New() e.GET("/", func(c echo.Context) error {return c.Blob(http.StatusOK, "image/png", content) }) e.Logger.Fatal(e.Start(":8989"))}
目录结构如下:.├── main.go└── static└── logo.png
编译运行后 , 可以将二进制文件移到任何地方运行 , 浏览器访问 http://localhhost:8989 , 能够正确显示 logo 图片表示成功了 。基于 Gin 框架 , 代码类似:
package mainimport (_ "embed""net/http""github.com/gin-gonic/gin")//go:embed static/logo.pngvar content []bytefunc main() {router := gin.Default()router.GET("/", func(ctx *gin.Context) {ctx.Data(http.StatusOK, "image/png", content)})router.Run(":8989")}
直接使用 net/http 库 , 代码如下:package mainimport (_ "embed""log""net/http""fmt")//go:embed static/logo.pngvar content []bytefunc main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {w.Header().Add("Content-Type", "image/png")w.WriteHeader(http.StatusOK)fmt.Fprintf(w, "%s", content)})log.Fatal(http.ListenAndServe(":8989", nil))}
例 2:内嵌文件 — 命令行应用简单的 Hello World:package mainimport (_ "embed""fmt")//go:embed message.txtvar message stringfunc main() {fmt.Println(message)}
其中 messaeg.txt 中的内容是 Hello World 。 目录结构如下:.├── main.go└── message.txt
编译后 , 可以将二进制移到任何地方 , 运行输出 Hello World(即 messaeg.txt 中的内容) 。例 3:内嵌目录 - 命令行应用以下程序将 static 目录内嵌到二进制程序中 , 然后在当前目录创建 static 目录中的所有文件 。
package mainimport ( "embed" "io" "log" "os" "path")//go:embed staticvar local embed.FSfunc main() { fis, err := local.ReadDir("static") if err != nil {log.Fatal(err) } for _, fi := range fis {in, err := local.Open(path.Join("static", fi.Name()))if err != nil {log.Fatal(err)}out, err := os.Create("embed-" + path.Base(fi.Name()))if err != nil {log.Fatal(err)}io.Copy(out, in)out.Close()in.Close()log.Println("exported", "embed-"+path.Base(fi.Name())) }}
该示例的目录结构和例 1 一样 。 编译后 , 可以将二进制文件移到任何地方 , 运行后 , 会在当前目录输出以 embed- 开头的文件 。例 4:内嵌目录 — Web 应用基于 Echo 框架:
package mainimport ("embed""net/http""github.com/labstack/echo/v4")//go:embed staticvar local embed.FSfunc main() {e := echo.New()e.GET("/*", echo.WrapHandler(http.FileServer(http.FS(local))))e.Logger.Fatal(e.Start(":8989"))}
同样 , 目录结构和 example1 一致 。 编译后运行 , 访问 http://localhost:8989 , 看到如下界面:文章插图
注意上面使用的是 /* , 如果直接使用 / , 点击链接会是 404 。
换成 Gin , 代码如下:
package mainimport ("embed""net/http""github.com/gin-gonic/gin")//go:embed static/*var local embed.FSfunc main() {router := gin.Default()router.GET("/*filepath", gin.WrapH(http.FileServer(http.FS(local))))router.Run(":8989")}
- 空调|让格力、海尔都担忧,中国取暖“新潮物”强势来袭,空调将成闲置品?
- 采用|消息称一加9系列将推出三款新机,新增一加9E
- 美国|英国媒体惊叹:165个国家采用北斗将GPS替代,连美国也不例外?
- 通气会|12月4~6日,2020中国信息通信大会将在成都举行
- 黑莓(BB.US)盘前涨逾32%,将与亚马逊开发智能汽车数据平台|美股异动 | US
- 荣耀V30|麒麟990+40W快充,昔日猛将彻底沦为清仓价?网友:太遗憾
- 网络覆盖|爱立信:2020年底,将有超过10亿人口获得5G网络覆盖
- 砍单|iPhone12之后,拼多多又将iPhone12Pro拉下水
- 短视频平台|大数据佐证,抖音带动三千万就业,视频手机将成生产力工具?
- 社区团购|你在买菜APP上薅的每一根羊毛,都将加倍奉还!