Встраивание статических ресурсов в проект Go
Я хотел создать небольшое автономное веб-приложение на Go, противоположное обычному веб-приложению, где ресурсы будут обслуживаться отдельно через CDN или HTTP-сервер, такой как Nginx. Но если производительность не имеет значения или она нацелена на небольшой трафик, то наличие автономного приложения облегчает его развертывание и распространение, поскольку это просто исполняемый двоичный файл.
Существует несколько пакетов, которые позволяют встраивать ресурсы в приложение Go:
Я не буду вдаваться в подробности каждой библиотеки, но я предпочел подход bindata, более простой для начала и активно поддерживаемый. Кроме того, шаг для встраивания ресурсов очень явно прописывается в коде.
Во-первых, вам нужно будет настроить рабочее пространство Go. Если вы не знакомы с Go, то вы можете обратиться к документации или моему предыдущему сообщению по этой теме.
После того, как вы получили рабочее пространство Go и настройку проекта, давайте создадим index.html
внутри каталога frontend/
в вашем проекте. Со следующим контентом (Обратите внимание что пробел после < нужно убрать):
< html> < body> Hello, World! < /body> < /html>
Теперь, когда у нас есть настройка проекта и статический ресурс для тестирования, давайте установим bindata с помощью команды:
go get -u github.com/jteeuwen/go-bindata/...
Мы готовы запустить бэкэнд-код веб-приложения. Создайте файл main.go
и скопируйте следующий код:
package mainimport ( "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-bindata
при вызове go generate
. Начиная с версии 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, в противном случае мы возвращаем содержимое ресурса.
Остальная часть кода предназначена для создания веб-приложения и связывания нашего шаблона static_handler
с соответствием всеми входящим запросам на /
. Если у вас возникли проблемы с пониманием этого кода, посмотрите документацию к пакету http
.
В качестве быстрого напоминания о том, как Go обрабатывает пакеты, все идентификаторы будут автоматически экспортированы в другие пакеты с тем же именем, если первая буква имени идентификатора начинается с заглавной буквы.
Основываясь на этом правиле, файл bindata.go
предоставляет функцию Asset
для пакета main
. Это загружает и возвращает русурс для данного имени. Он возвращает ошибку, если ресурс не может быть найден или не может быть загружен.