Допустим, у нашего приложения есть 3 среды — разработка, подготовка и производство. У нас могут быть разные конфигурации для каждой из этих сред, таких как серверные конечные точки, ключи API аналитики, ключи API отчетов об ошибках, настройки, такие как отключение журналов отладки в производственной среде и т. д.
Существует три распространенных способа управления этими конфигурациями:
1. Внедрение во время сборки. Для каждой среды создайте отдельный пакет и внедрите конфигурацию, специфичную для среды, в код.
2. Разрешение среды выполнения. Храните конфигурации для всех сред в одном пакете и динамически разрешайте нужную конфигурацию во время выполнения.
3. Удаленная загрузка — получение конфигурации из серверной части во время выполнения.
Поговорим о каждом из этих подходов, их плюсах и минусах.
Внедрение во время сборки
Приложения SPA обычно создаются с помощью сборщика и развертываются на веб-серверах или копируются в образ докера nginx и развертываются на контейнерных платформах.
При таком подходе для каждой среды создается отдельный пакет (или образ докера), а значения конфигурации для этой среды вводятся в пакет с использованием «переменных среды». Конечно, во внешнем интерфейсе нет такой вещи, как переменные среды, поэтому обычно это имитируется с помощью глобальных переменных.
Если вы используете webpack, create-react-app или vue-cli и т. д., вы можете получить доступ к значению конфигурации как process.env.YOUR_CONFIG_NAME
и т. д.
Недостатки:
- Поскольку конфигурация, специфичная для вашей среды, встроена в ваш пакет, вам необходимо создавать отдельные пакеты для каждой среды.
- Способ доступа к конфигурации кажется хакерским — вам нужно получить его из объекта process.env
, который не является частью API браузера.
- Вы не можете использовать это, если вы не используете упаковщик или инструмент сборки.
- Поскольку значения конфигурации будут вводиться из CI/CD, они, скорее всего, не будут контролироваться версиями.
Преимущества:
- Поскольку каждый пакет содержит только конфигурацию для определенной среды, злоумышленники не смогут узнать о существовании других сред и их конфигураций, таких как серверные конечные точки и т. д., просмотрев пакет. Это обеспечивает небольшую безопасность в виде безопасности через неясность, но на нее не следует серьезно полагаться.
Разрешение во время выполнения
В качестве альтернативы мы можем хранить конфигурации для всех сред в исходном коде и динамически загружать соответствующую конфигурацию для каждой среды. Обычно разные среды имеют разные URL-адреса, и мы можем использовать это для загрузки правильной конфигурации.
Допустим, у нас есть 3 среды — разработка, подготовка и производство, которые имеют следующие URL-адреса — dev.myapp.com
, staging.myapp.com
и www.myapp.com
соответственно.
Конфигурации для этих трех сред можно хранить в dev.config.json
, staging.config.json
и prod.config.json
.
// dev.config.json { "API_URL": "dev.myapp.com/api", "ANALYTICS_KEY": "xxxaaa", "ERROR_REPORTING_KEY": "xxxeee", "IS_LOGGING_ENABLED": true } // staging.config.json { "API_URL": "staging.myapp.com/api", "ANALYTICS_KEY": "xxxaaa", "ERROR_REPORTING_KEY": "xxxeee", "IS_LOGGING_ENABLED": true } // prod.config.json { "API_URL": "www.myapp.com/api", "ANALYTICS_KEY": "yyyaaa", "ERROR_REPORTING_KEY": "yyyeee", "IS_LOGGING_ENABLED": false }
Мы можем использовать window.location.hostname
, чтобы решить, какую конфигурацию загружать во время выполнения:
// Config.js import prod from "./prod.config.json"; import staging from "./staging.config.json"; import dev from "./dev.config.json"; let config = {}; switch (window.location.hostname) { case "www.myapp.com": config = prod; break; case "staging.myapp.com": config = staging; break; case "dev.myapp.com": config = dev; break; default: config = dev; } export default config;
Это может быть использовано в приложении как
// ApiClient.js import axios from "axios"; import Config from "../Config"; const ApiClient = axios.create({ baseURL: Config.API_URL }); export default ApiClient;
Обычно некоторые значения конфигурации повторяются для разных сред. Например, вы можете решить использовать один и тот же ключ API аналитики для всех непроизводственных сред. Мы можем сделать конфиги СУХИМИ, извлекая эти общие значения конфигов в common.config.json
// common.config.json { "ANALYTICS_KEY": "xxxaaa", "ERROR_REPORTING_KEY": "xxxeee", "IS_LOGGING_ENABLED": true } // dev.config.json { "API_URL": "dev.myapp.com/api" } // staging.config.json { "API_URL": "staging.myapp.com/api" } // prod.config.json { "API_URL": "www.myapp.com/api", "ANALYTICS_KEY": "yyyaaa", "ERROR_REPORTING_KEY": "yyyeee", "IS_LOGGING_ENABLED": false }
конфиги можно объединить в Config.js
// Config.js import common from "./common.config.json"; import prod from "./prod.config.json"; import staging from "./staging.config.json"; import dev from "./dev.config.json"; let config = {}; switch (window.location.hostname) { case "www.myapp.com": config = { ...common, ...prod }; break; case "staging.myapp.com": config = { ...common, ...staging }; break; case "dev.myapp.com": config = { ...common, ...dev }; break; default: config = { ...common, ...dev }; } export default config;
Преимущества:
- Один и тот же пакет (или образ докера) можно использовать для всех сред.
- Работает для проектов, в которых не используются упаковщики или инструменты сборки.
- Значения конфигурации контролируются версиями, и на них легко ссылаться, поскольку они находятся в одной кодовой базе.
Недостатки:
- Вы раскрываете существование других сред злоумышленникам. Это может быть проблемой, если вы не уверены в безопасности вашей надежной инфры.
Удаленная загрузка
Как правило, сборка внешнего интерфейса не занимает много времени, поэтому легко развернуть изменения конфигурации для пользователей в течение нескольких минут. Но иногда вам может понадобиться изменить конфигурацию из бэкэнда:
- Используйте разные наборы конфигураций для разных сегментов пользователей — A/B-тестирование, поэтапное развертывание, функциональные флаги и т. д.
- Обходные процессы — на некоторых предприятиях приходится выполнять множество процессов, чтобы развернуть одно изменение на производственной площадке. В таких случаях полезно получить некоторые конфигурации из бэкэнда.
Несмотря на эти преимущества, тот факт, что мы извлекаем их из серверной части, усложняет ситуацию — нам нужно проектировать код/интерфейс с учетом задержки и реализовать кэширование таким образом, чтобы оно не подрывало упомянутые выше преимущества. Этот подход обычно используется вместе с любым из первых двух подходов.
Спасибо за чтение! :)
Первоначально опубликовано на sheshbabu.com