Golang一般用到embed package的主要场景就是Web server需要携带html css js等静态文件。
使用embed directive可以让外部文件在编译时自动加入到二进制程序中。这样我们如果要分发程序,只需一个二进制文件,不需要外带任何其他资源文件。
而我们在代码中去引用embedded文件有三种方法(类型):string
, []byte
和 FS
但实际上,embed还是有一些限制的,本文就详细讲讲这些限制是什么,以及如何曲线救国。
文件层级问题
如果embed directive与被embedded的文件不在同一级(文件系统中)。
比如说
│ main.go
│
├─server
│ handler.go
│
└─tepl
index.html
如果handler.go试图去包含tepl文件夹里的文件:
// handler.go
//go:embed tepl
var s embed.FS
embed pattern将无法被成功解析,因为被引用者的文件层级高于引用者。
除了将被引用者的文件层级降至同一级或更低,还有一种方法就是直接在main.go这样同级的文件中进行处理,然后传递给需要的包中。
// main.go
//go:embed tepl
var tepl embed.FS
func main() {
handler.injectFS(&tepl)
}
目前来说,没有其他更好的解决方法了。
复杂路径问题
假如我们在tepl中放入一个static文件夹:
│ main.go
│
└─server
│ handler.go
│
└─tepl
│ index.html
│
└─static
main.css
在handler.go中,我们用http.FileServer来处理对静态文件们的请求:
//go:embed tepl
var tepl embed.FS
func handle() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(tepl))))
}
很自然地,定义的是/static/
的路由,而不是/
,因为根路径常常要处理其他事情。
但此时由于 embed 的局限,如果我们要获取mian.css,就需要访问这个路径/static/tepl/static/main.css
解决的方法也很简单,用 io.fs
包中的Sub方法即可:
var tepl embed.FS
func handle() {
sub, _ := fs.Sub(tepl, "tepl/static")
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(sub))))
}
Refs