从Golang 1.16开始,Go中支持文件嵌入,而无需外部软件包。我一直在使用pkgr和packr之类的软件包,以便更轻松地将静态文件嵌入go二进制文件中。在本文中,我们将探讨新//go:embed指令的用法。


为什么需要静态文件嵌入?
在某些情况下,我们希望将静态 文件嵌入二进制文件中。虽然可以构建从磁盘读取静态文件的二进制文件,但将其运送给最终用户通常很麻烦,因为静态文件必须位于用户设备上的某个位置,或者该位置必须是可配置的。最重要的是,在将二进制文件升级或移动到新位置时,用户必须记住要更新所有文件/配置引用。
以下是一些经常使用静态文件嵌入的常见用例:
Go模板:二进制文件需要模板文件。对于Web服务器二进制文件或CLI应用程序,这是一个相当常见的用例,init其中提供了创建示例项目的命令。在没有嵌入的情况下,模板通常内联在代码中。例如:参见qbec init或source。
静态网络服务器:有时静态文件(例如index.htmlHTML或其他HTML,JavaScript和CSS文件)需要与golang服务器二进制文件一起提供,以便用户可以运行服务器并提供这些文件。例如:静态文件嵌入到Web服务器中
数据库迁移:可以使用嵌入式文件的另一个地方是附带二进制文件的数据库迁移脚本。例如:数据库迁移文件
使用go embed指令
使用embed指令的第一件事是确保您至少使用了golang 1.16。对于旧版本的Go,请考虑使用pkgr。
我们将编写一个运行网络应用程序的应用程序,该应用程序会在网页中回显该URL(是!!)
该程序从静态title.txt文件中读取网页标题,css/main.css通过/static/路由提供静态文件(),并使用go模板index.html.tmpl通过HTTP端口3000呈现所有路由。使用新的embed指令将所有静态文件和模板嵌入到二进制文件中。
项目结构:

├──go.mod
├──main.go
├──静态
│└──CSS
│└──的main.css
├──模板
│└──index.html.tmpl
└──title.txt

package main

import (
"embed"
"html/template"
"log"
"net/http"
)

// The go embed directive statement must be outside of function body

// Embed the file content as string.
//go:embed title.txt
var title string

// Embed the entire directory.
//go:embed templates
var indexHTML embed.FS

//go:embed static
var staticFiles embed.FS

func main() {

// Note the call to ParseFS instead of Parse
t, err := template.ParseFS(indexHTML, "templates/index.html.tmpl")
if err != nil {
    log.Fatal(err)
}

// http.FS can be used to create a http Filesystem
var staticFS = http.FS(staticFiles)
fs := http.FileServer(staticFS)

// Serve static files
http.Handle("/static/", fs)
// Handle all other requests
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    var path = req.URL.Path
    log.Println("Serving request for path", path)
    w.Header().Add("Content-Type", "text/html")

    // respond with the output of template execution
    t.Execute(w, struct {
        Title    string
        Response string
    }{Title: title, Response: path})

})

log.Println("Listening on :3000...")
// start the server
err = http.ListenAndServe(":3000", nil)
if err != nil {
    log.Fatal(err)
}

}

带有go embed的示例Web服务器

{{.Title}}

{{.Response}}

Powered by // go:embed

网页模板:index.html.tmpl

让我们构建和部署Web服务器。
$ go版本
go版本go1.16 darwin / arm64
$去建立。#构建二进制文件
$ cp ./go-embed / tmp /#复制到temp目录。这将有助于验证静态文件是否已实际嵌入
$ cd / tmp && ./go-embed#运行服​​务器
2020/12/18 12:21:15收听:3000 …
2020/12/18 12:21:23服务请求路径/ some-path-with-css-applied
2020/12/18 12:21: 23路径/favicon.ico的
服务请求2020/12/18 12:21:24路径/ some-path-with-css-applied
2020/12/18 12:21:24路径的服务请求路径/ favicon的服务请求。 ico
2020/12/18 12:21:25路径的服务请求/ some-path-with-css-applied
2020/12/18 12:21:25路径的服务请求/favicon.ico
浏览到http:// localhost:3000 /

Web服务器提供通过go embed嵌入的内容
最终结果是准备分发的单个Web服务器二进制文件。有关更多信息,请查看官方嵌入文档。嵌入愉快。