В файле main.go
нашего веб-приложения сейчас есть несколько настроек конфигурации которых нельзя менять из вне, и это проблематично.
Содержание статьи
- Значения по умолчанию в командной строке
- Преобразования типов из командной строки
- Справка к флагам командной строки
- Переменные среды в Go
- Булевые значения из командной строки
- Предварительно существующие переменные
Настройки которые нужно указать в командной строке при запуске веб-приложения:
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
- Сетевой адрес на котором будет работать приложение (сейчас он
":4000"
); - Путь к папке со статическими файлами (сейчас он
"./ui/static"
).
Эти «вшитые» настройки являются плохим решением. В них нет разделения между кодом и настройками, которые могут меняться. Мы не можем менять настройки во время запуска веб-приложения, что важно, если вам нужны разные стартовые настройки на стадии разработки, тестирования или продакшена.
В этом уроке мы начнем улучшать данный аспект приложения и реализуем возможность менять IP адрес нашего приложения при его запуске.
В Go, популярным способом управления параметрами конфигурации является использование флагов из командной строки при запуске приложения. Например:
1 |
$ go run ./cmd/web -addr=":80" |
Вот простой способ получить значение флага из командной строки в нашем приложении:
1 |
addr := flag.String("addr", ":4000", "Сетевой адрес HTTP") |
По сути, данный код определяет новый флаг командной строки с названием addr
, значением по умолчанию ":4000"
и коротким текстом для справки, объясняющим, что данный флаг в себе содержит. Во время запуска веб-приложения, значение флага будет сохранено в переменной addr
.
Добавим поддержку данного флага в нашем приложении и заменим изначально вшитый сетевой адрес на значение флага из командной строки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package main import ( "flag" "log" "net/http" ) func main() { // Создаем новый флаг командной строки, значение по умолчанию: ":4000". // Добавляем небольшую справку, объясняющая, что содержит данный флаг. // Значение флага будет сохранено в переменной addr. addr := flag.String("addr", ":4000", "Сетевой адрес HTTP") // Мы вызываем функцию flag.Parse() для извлечения флага из командной строки. // Она считывает значение флага из командной строки и присваивает его содержимое // переменной. Вам нужно вызвать ее *до* использования переменной addr // иначе она всегда будет содержать значение по умолчанию ":4000". // Если есть ошибки во время извлечения данных - приложение будет остановлено. flag.Parse() mux := http.NewServeMux() mux.HandleFunc("/", home) mux.HandleFunc("/snippet", showSnippet) mux.HandleFunc("/snippet/create", createSnippet) fileServer := http.FileServer(http.Dir("./ui/static/")) mux.Handle("/static/", http.StripPrefix("/static", fileServer)) // Значение, возвращаемое функцией flag.String(), является указателем на значение // из флага, а не самим значением. Нам нужно убрать ссылку на указатель // то есть перед использованием добавьте к нему префикс *. Обратите внимание, что мы используем // функцию log.Printf() для записи логов в журнал работы нашего приложения. log.Printf("Запуск сервера на %s", *addr) err := http.ListenAndServe(*addr, mux) log.Fatal(err) } |
PS: Прошу заметить, что мы убрали созданный ранее фильтр neuteredFileSystem который мы использовали в прошлой статье. Данный фильтр помогал в проверке файла
index.html
при прямом URL переходе в папку со статическими файлами, и возвращал ошибку 404 — страница не найдена. Это было сделано с целью экономии кода в следующих статьях. В конце мы его вернем на свое место.
Сохраните данный main.go
файл и попробуйте использовать флаг -addr
при запуске веб-приложения из командной строки. Вы обнаружите, что теперь сервер будет использовать указанный вами сетевой адрес и порт следующим образом:
1 2 |
go run ./cmd/web -addr="127.0.0.1:9999" 2021/01/21 16:15:12 Запуск сервера на 127.0.0.1:9999 |
На заметку: Порты в интервале от 0 до 1023 ограничены и (обычно) могут использоваться только службами с правами администратора. При попытке использовать один из этих портов, при запуске приложения из терминала, вы получите сообщение об ошибке
bind: permission denied
.
Значения по умолчанию в командной строке
Флаги командной строки не являются обязательными. К примеру, если вы запустите веб-приложение без флага -addr
, сервер будет использовать адрес :4000
(это указанное нами значение по умолчанию).
1 2 |
go run ./cmd/web 2021/01/21 16:20:00 Запуск сервера на :4000 |
Нет никаких правил касательно использования значений по умолчанию в качестве флагов командной строки. Многим нравится использовать значения по умолчанию, которые имеют смысл для среды разработки, потому что они экономят время избавляя разработчиков от необходимости каждый раз указывать одни и те же данные. Но все зависит от ситуации. Вместо этого вы можете выбрать более безопасный подход, задав значения по умолчанию для вашей продакшен среды.
Преобразования типов из командной строки
В приведенном выше коде, при определении флага командной строки мы использовали функцию flag.String()
. Она преобразует любое значение из командной строки в тип string. Если значение не может быть преобразовано в string
, приложение записывает ошибку в журнал и завершает работу.
В Go, также есть ряд других функций, включая flag.Int()
, flag.Bool()
и flag.Float64()
. Они работают точно так же, как flag.String()
, за исключением того, что они автоматически преобразуют значение флага командной строки в соответствующий им тип.
Справка к флагам командной строки
Другой приятной особенностью является то, что вы можете использовать флаг -help
для ознакомления со списком доступных флагов командной строки для приложения и небольшой документацией (справки) к ним. Посмотрим на данную возможность в деле:
1 2 3 4 |
go run ./cmd/web -help Usage of /tmp/go-build303819331/b001/exe/web: -addr string Сетевой адрес HTTP (default ":4000") |
Мы реализовали возможность управления параметрами конфигурации для нашего приложения во время его запуска, а также получили понятный и задокументированный интерфейс между приложением и его доступными настройками.
Переменные среды в Go
Если вы раньше создавали и запускали веб-приложения, вы могли задуматься о переменных среды. Хорошая ли это практика — хранить там настройки конфигурации к нашему приложению?
Вы можете хранить свои настройки конфигурации в переменных среды и получить к ним доступ непосредственно из вашего приложения, используя функцию os.Getenv() следующим образом:
1 |
addr := os.Getenv("SNIPPETBOX_ADDR") |
Однако, у этого способа есть недостатки по сравнению с использованием флагов командной строки напрямую. Вы не можете указать настройки по умолчанию (возвращаемое значение из os.Getenv()
будет пустой строкой, если такая переменная среды не существует) и у вас не будет возможности применить -help
, которая подскажет, чем занимается конкретный флаг, и возвращаемое значение из os.Getenv()
всегда является строкой.
Вы не получите автоматического преобразования типов, как в случае с flag.Int()
и другими функциями для работы с командной строкой.
Вместо этого можно воспользоваться преимуществами обоих способов, передав переменную среды в качестве флага командной строки при запуске приложения. К примеру:
1 2 3 |
$ export SNIPPETBOX_ADDR=":9999" $ go run ./cmd/web -addr=$SNIPPETBOX_ADDR 2021/01/21 16:20:00 Запуск сервера на :9999 |
Булевые значения из командной строки
Для флагов, созданных с помощью функции flag.Bool()
, значение задается выражением -flag=true
. Следующие две команды эквивалентны:
1 2 |
$ go run example.go -flag=true $ go run example.go -flag |
Если вы хотите указать значение false
булеву флагу, то нужно написать -flag=false
напрямую.
Предварительно существующие переменные
Можно спарсить значения флагов командной строки в уже существующие переменные, используя flag.StringVar(), flag.IntVar(), flag.BoolVar() и другие функции. Это может быть полезно, если требуется сохранить все параметры конфигурации в одной структуре. Далее дан грубоватый пример в обучающих целях:
1 2 3 4 5 6 7 8 9 10 11 |
type Config struct { Addr string StaticDir string } ... cfg := new(Config) flag.StringVar(&cfg.Addr, "addr", ":4000", "HTTP network address") flag.StringVar(&cfg.StaticDir, "static-dir", "./ui/static", "Path to static assets") flag.Parse() |
Скачать исходный код
Ниже предоставлен исходный код для сайта на Golang с нуля.
Скачать: snippetbox-10.zip
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»