我想在 Go 中创建一个小型独立 Web 应用程序,这与常规 Web 应用程序相反,在常规 Web 应用程序中,资源将通过 CDN 或 HTTP 服务器(例如 Nginx)单独提供。
但是,如果性能不是关键问题或者应用程序旨在用于低流量,则使用独立应用程序可以简化部署和分发,因为它只是一个可执行二进制文件。
有几个包可用于将资源嵌入到 Go 应用程序中:
我不会深入研究每个库的具体细节,但我更喜欢bindata方法,因为它易于使用且得到积极支持。
首先,让我们在项目的frontend/
目录中创建一个index.html
:
<html> <body> Hello, World! </body> </html>
现在我们已经有了一个项目设置和一个要测试的静态资源,让我们使用以下命令安装bindata :
go get -u github.com/jteeuwen/go-bindata/...
我们已准备好运行 Web 应用程序的后端代码。创建main.go
文件,并复制以下代码:
package main import ( "bytes" "io" "net/http" ) //go:generate go-bindata -prefix "frontend/" -pkg main -o bindata.go frontend/... func static_handler(rw http.ResponseWriter, req *http.Request) { var path string = req.URL.Path if path == "" { path = "index.html" } if bs, err := Asset(path); err != nil { rw.WriteHeader(http.StatusNotFound) } else { var reader = bytes.NewBuffer(bs) io.Copy(rw, reader) } } func main() { http.Handle("/", http.StripPrefix("/", http.HandlerFunc(static_handler))) http.ListenAndServe(":3000", nil) }
此代码中的重要行:
//go:generate go-bindata -prefix "frontend/" -pkg main -o bindata.go frontend/...
上面的行允许我们在调用go generate
时运行go-bindata
命令。从版本 1.4 开始,您可以在生成阶段运行自定义命令。只需将//go:generate command argument...
添加到您的 go 文件即可。
go-bindata
命令行有多个参数,因此请查看文档以了解如何使用它。在我们的例子中,我们说:
-prefix "frontend/"
定义静态路径名的一部分
-pkg main
定义生成代码中使用的包名称
-o bindata.go
定义生成文件的名称
运行go generate
命令后,您应该会看到一个名为bindata.go
的生成文件。您的项目的结构应该如下所示:
. │ ├── bindata.go (auto-generated file) ├── frontend │ └── index.html └── main.go
提供静态文件的逻辑在static_handler
函数中,该函数接收请求并检查路径是否与静态路径匹配。检查是使用Asset
函数完成的,由bindata.go
用户自动导出。如果资源不存在,我们返回404
,否则,我们返回资源的内容。
其余代码用于创建 Web 应用程序并绑定我们的static_handler
模板以匹配/
的所有传入请求。如果您无法理解此代码,请查看http package
的 Go 官方文档。
快速提醒一下 Go 如何处理包,如果标识符名称的第一个字母以大写字母开头,则所有标识符将自动导出到具有相同名称的其他包。
基于这个规则, bindata.go
文件main
包提供了Asset
功能。这会加载并返回给定名称的资源。如果找不到或无法加载资源,它将返回错误。