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