С помощью Firebase Hosting вы можете настроить индивидуальное поведение хостинга для запросов к вашему сайту.
Что можно настроить для Hosting ?
Укажите, какие файлы в локальном каталоге проекта вы хотите развернуть на Firebase Hosting . Узнайте, как это сделать.
Отображайте персонализированную страницу ошибки 404/«Страница не найдена». Узнайте, как это сделать.
Настройте
redirectsдля страниц, которые вы переместили или удалили. Узнайте, как это сделать.Настройте
rewritesдля любой из этих целей:Отображение одного и того же контента для нескольких URL-адресов. Узнайте, как это сделать.
Запустите функцию или получите доступ к контейнеру Cloud Run по URL-адресу Hosting . Узнайте, как это сделать: функция или контейнер .
Создайте собственную Dynamic Link для домена. Узнайте, как это сделать.
Добавьте
headersдля передачи дополнительной информации о запросе или ответе, например, о том, как браузеры должны обрабатывать страницу и ее содержимое (аутентификация, кэширование, кодирование и т. д.). Узнайте, как это сделать.Настройте правила интернационализации (i18n) для отображения определенного контента в зависимости от языковых предпочтений пользователя и/или страны. Подробнее (на другой странице).
Где вы задаёте конфигурацию Hosting ?
Конфигурацию Firebase Hosting вы определяете в файле firebase.json . Firebase автоматически создает файл firebase.json в корневом каталоге вашего проекта при выполнении команды firebase init .
Полный пример конфигурации firebase.json (только для Firebase Hosting ) вы найдете внизу этой страницы. Обратите внимание, что файл firebase.json может также содержать конфигурации для других сервисов Firebase .
Вы можете проверить содержимое развернутого файла firebase.json , используя REST API Hosting .
Порядок приоритета ответов Hosting
Различные параметры конфигурации Firebase Hosting , описанные на этой странице, иногда могут пересекаться. В случае конфликта Hosting определяет свой ответ, используя следующий порядок приоритетов:
- Зарезервированные пространства имен, начинающиеся с сегмента пути
/__/* - Настроенные перенаправления
- Точное совпадение статического контента
- Настроенные правила перезаписи
- Пользовательская страница 404
- Страница 404 по умолчанию
Если вы используете перезапись i18n , порядок приоритетов точного совпадения и обработки ошибки 404 расширяется, чтобы учесть ваш "контент i18n".
Укажите, какие файлы следует развернуть.
Атрибуты по умолчанию — public и ignore — включенные в стандартный файл firebase.json , определяют, какие файлы в каталоге вашего проекта должны быть развернуты в вашем проекте Firebase.
Конфигурация hosting по умолчанию в файле firebase.json выглядит следующим образом:
"hosting": {
"public": "public", // the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
публичный
Необходимый
Атрибут public указывает, в какой директории следует развернуть приложение на Firebase Hosting . Значение по умолчанию — директория с именем public , но вы можете указать путь к любой директории, если она существует в директории вашего проекта.
Ниже приведено имя каталога для развертывания, указанное по умолчанию:
"hosting": {
"public": "public"
// ...
}
Вы можете изменить значение по умолчанию на каталог, в который хотите выполнить развертывание:
"hosting": {
"public": "dist/app"
// ...
}
игнорировать
Необязательный
Атрибут ignore указывает файлы, которые следует игнорировать при развертывании. Он может использовать шаблоны (globs) так же, как Git обрабатывает файл .gitignore .
Ниже приведены значения по умолчанию для файлов, которые следует игнорировать:
"hosting": {
// ...
"ignore": [
"firebase.json", // the Firebase configuration file (the file described on this page)
"**/.*", // files with a leading period should be hidden from the system
"**/node_modules/**" // contains dependencies used to create your site but not run it
]
}
Настройка страницы 404/«Страница не найдена»
Необязательный
Вы можете выводить пользовательскую ошибку 404 Not Found когда пользователь пытается получить доступ к несуществующей странице.
Создайте новый файл в public директории вашего проекта, назовите его 404.html , а затем добавьте в него свой собственный контент для сообщения об ошибке 404 Not Found .
Если браузер выдаст ошибку 404 Not Found на вашем домене или поддомене, Firebase Hosting отобразит содержимое этой пользовательской страницы 404.html
Настройка перенаправлений
Необязательный
Используйте перенаправление URL-адресов, чтобы предотвратить неработающие ссылки, если вы переместили страницу, или для сокращения URL-адресов. Например, вы можете перенаправить браузер с example.com/team на example.com/about.html .
Для настройки перенаправлений URL-адресов создайте атрибут ` redirects , содержащий массив объектов (называемых «правилами перенаправления»). В каждом правиле укажите шаблон URL-адреса, который, если он совпадает с путем URL-адреса запроса, запускает перенаправление Hosting на указанный целевой URL-адрес.
Вот базовая структура атрибута redirects . В этом примере запросы на /foo перенаправляются на /bar путем отправки нового запроса.
"hosting": {
// ...
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
} ]
}
"hosting": {
// ...
// Add the "redirects" attribute within "hosting"
"redirects": [ {
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
// Returns a permanent redirect to "/bar" for requests to both "/foo" and "/foo/**"
"source": "/foo{,/**}"
"destination": "/bar"
"type": 301
}, {
// Returns a temporary redirect for all requests to files or directories in the "firebase" directory
"source": "/firebase/**",
"destination": "https://firebase.google.com/",
"type": 302
}, {
// A regular expression-based redirect equivalent to the above behavior
"regex": "/firebase/.*",
"destination": "https://firebase.google.com/",
"type": 302
} ]
}
Атрибут redirects содержит массив правил перенаправления, причем каждое правило должно включать поля из приведенной ниже таблицы.
Firebase Hosting сравнивает значение source или regex со всеми путями URL в начале каждого запроса (до того, как браузер определит, существует ли файл или папка по этому пути). Если совпадение найдено, исходный сервер Firebase Hosting отправляет ответ перенаправления HTTPS, сообщая браузеру о необходимости выполнить новый запрос по destination URL.
| Поле | Описание | |
|---|---|---|
redirects | ||
source (рекомендуется)или regex | Шаблон URL-адреса, совпадение с исходным URL-адресом запроса которого запускает перенаправление со стороны Hosting .
| |
destination | Статический URL-адрес, по которому браузер должен отправить новый запрос. Этот URL-адрес может быть относительным или абсолютным. | |
type | Код ответа HTTPS
| |
Захват сегментов URL-адресов для перенаправлений.
Необязательный
Иногда может потребоваться выделить определенные сегменты шаблона URL-адреса правила перенаправления ( source или значение regex ), а затем повторно использовать эти сегменты в destination пути правила.
Если вы используете поле source (то есть указываете шаблон URL-адреса), вы можете захватывать сегменты, добавляя префикс : для идентификации сегмента. Если вам также необходимо захватить оставшийся путь URL-адреса после сегмента, добавьте символ " * сразу после сегмента. Например:
"hosting": { // ... "redirects": [ { "source": "/blog/:post*", // captures the entire URL segment beginning at "post" "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the "source" value "type": 301 }, { "source": "/users/:id/profile", // captures only the URL segment "id", but nothing following "destination": "/users/:id/newProfile", // includes the URL segment identified and captured by the "source" value "type": 301 } ] }
Если вы используете поле regex (то есть указываете регулярное выражение RE2 для шаблона URL), вы можете захватывать сегменты, используя именованные или неименованные группы захвата RE2. Именованные группы захвата можно использовать в поле destination с префиксом : ", а на неименованные группы захвата можно ссылаться по их числовому индексу в значении regex , начиная с 1. Например:
"hosting": { // ... "redirects": [ { "regex": "/blog/(?P<post>.+)", // if you're familiar with PCRE, be aware that RE2 requires named capture groups to begin with ?P "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the `regex` value "type": 301 }, { "regex": "/users/(\d+)/profile", // uses the \d directive to only match numerical path segments "destination": "/users/:1/newProfile", // the first capture group to be seen in the `regex` value is named 1, and so on "type": 301 } ] }
Настройка перезаписи
Необязательный
Используйте перезапись, чтобы отображать один и тот же контент для нескольких URL-адресов. Перезапись особенно полезна при сопоставлении с шаблоном, поскольку вы можете принять любой URL-адрес, соответствующий шаблону, и позволить клиентскому коду решить, что отображать.
Также можно использовать правила перезаписи для поддержки приложений, использующих HTML5 pushState для навигации. Когда браузер пытается открыть URL-адрес, соответствующий указанному source или шаблону regex , браузеру будет предоставлено содержимое файла по destination URL-адресу.
Настройте перезапись URL-адресов, создав атрибут rewrites , содержащий массив объектов (называемых «правилами перезаписи»). В каждом правиле укажите шаблон URL-адреса, который, если он совпадает с путем URL-адреса запроса, заставляет Hosting отвечать так, как если бы сервису был предоставлен указанный целевой URL-адрес.
Вот базовая структура атрибута rewrites . В этом примере для запросов к несуществующим файлам или каталогам используется index.html .
"hosting": {
// ...
// Serves index.html for requests to files or directories that do not exist
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
}
"hosting": { // ... // Add the "rewrites" attribute within "hosting" "rewrites": [ { // Serves index.html for requests to files or directories that do not exist "source": "**", "destination": "/index.html" }, { // Serves index.html for requests to both "/foo" and "/foo/**" // Using "/foo/**" only matches paths like "/foo/xyz", but not "/foo" "source": "/foo{,/**}", "destination": "/index.html" }, { // A regular expression-based rewrite equivalent to the above behavior "regex": "/foo(/.*)?", "destination": "/index.html" }, { // Excludes specified pathways from rewrites "source": "!/@(js|css)/**", "destination": "/index.html" } ] }
Атрибут rewrites содержит массив правил перезаписи, причем каждое правило должно включать поля из приведенной ниже таблицы.
Firebase Hosting применяет правило перезаписи только в том случае, если файл или каталог не существует по пути URL, соответствующему указанному source или шаблону regex URL. Когда запрос запускает правило перезаписи, браузер возвращает фактическое содержимое указанного destination файла вместо HTTP-перенаправления.
| Поле | Описание | |
|---|---|---|
rewrites | ||
source (рекомендуется)или regex | Шаблон URL-адреса, который, если совпадает с исходным URL-адресом запроса, запускает процесс перезаписи URL-адреса Hosting
| |
destination | Локальный файл, который должен существовать. Этот URL-адрес может быть относительным или абсолютным. | |
Направляйте запросы непосредственно в функцию.
Вы можете использовать rewrites для запуска функции по URL-адресу Firebase Hosting . Следующий пример — это фрагмент работы с динамическим контентом с помощью Cloud Functions .
Например, чтобы направлять все запросы со страницы /bigben на вашем Hosting на выполнение функции bigben :
"hosting": {
// ...
// Directs all requests from the page `/bigben` to execute the `bigben` function
"rewrites": [ {
"source": "/bigben",
"function": {
"functionId": "bigben",
"region": "us-central1" // optional (see note below)
"pinTag": true // optional (see note below)
}
} ]
}
Если
regionне указан в блокеfunctionв файлеhosting.rewrites, Firebase CLI пытается автоматически определить регион из исходного кода функции, который, если не указан, по умолчанию принимает значениеus-central1. Если исходный код функции недоступен, CLI пытается определить регион из развернутой функции. Если функция находится в нескольких регионах, CLI требует указанияregionв файлеhosting.rewrites.
Функция
pinTagдоступна только в Cloud Functions for Firebase (2-го поколения). С её помощью вы можете гарантировать синхронизацию каждой функции генерации динамического контента вашего сайта со статическими ресурсами Hosting и конфигурацией Hosting . Кроме того, эта функция позволяет предварительно просматривать изменения в функциях на каналах предварительного просмотра Hosting .Если добавить
"pinTag": trueв блокfunctionв файле конфигурацииhosting.rewrites, то функция "pinned" будет развернута вместе со статическими ресурсами и конфигурацией вашего Hosting , даже при выполнении. Если вы откатите версию своего сайта, функция "pinned" также будет откачена.firebase deploy --only hosting Эта функция основана на тегах Cloud Run , которые имеют ограничение в 1000 тегов на сервис и 2000 тегов на регион. Это означает, что после сотен развертываний самые старые версии сайта могут перестать работать.
После добавления этого правила перезаписи и развертывания в Firebase (с помощью firebase deploy ), ваша функция станет доступна по следующим URL-адресам:
Ваши поддомены Firebase:
PROJECT_ID .web.app/bigbenиPROJECT_ID .firebaseapp.com/bigbenЛюбые подключенные пользовательские домены :
CUSTOM_DOMAIN /bigben
Когда Firebase Hosting перенаправляет трафик в функцию, функция получает полный исходный путь запроса и строку запроса. Например, запрос к /bigben/hello/world?foo=bar на вашем сайте Hosting передается в функцию с полным путем и строкой запроса в неизменном виде. Убедитесь, что обработчик вашей функции написан таким образом, чтобы обрабатывать весь абсолютный URL , а не только базовый путь, определенный в переадресации.
При перенаправлении запросов к функциям с использованием Hosting поддерживаются следующие методы HTTP-запросов: GET , POST , HEAD , PUT , DELETE , PATCH и OPTIONS . Другие методы, такие как REPORT или PROFIND не поддерживаются.
Прямые запросы к контейнеру Cloud Run
Вы можете использовать rewrites для доступа к контейнеру Cloud Run по URL-адресу Firebase Hosting . Следующий пример — это фрагмент работы с динамическим контентом с помощью Cloud Run .
Например, чтобы перенаправить все запросы со страницы /helloworld на вашем Hosting на запуск и выполнение экземпляра контейнера helloworld :
"hosting": {
// ...
// Directs all requests from the page `/helloworld` to trigger and run a `helloworld` container
"rewrites": [ {
"source": "/helloworld",
"run": {
"serviceId": "helloworld", // "service name" (from when you deployed the container image)
"region": "us-central1" // optional (if omitted, default is us-central1)
}
} ]
}
Эта функция позволяет обеспечить синхронизацию изменений в службе Cloud Run для генерации динамического контента вашего сайта со статическими ресурсами Hosting и конфигурацией Hosting . Кроме того, эта функция позволяет предварительно просматривать ваши правила перезаписи в каналах предварительного просмотра Cloud Run на Hosting .
Если вы добавите
"pinTag": trueв блокrunв конфигурацииhosting.rewrites, ваши статические ресурсы и конфигурация Hosting будут привязаны к самой последней версии службы Cloud Run на момент развертывания. Если вы откатите версию своего сайта, версия "привязанной" службы Cloud Run также будет откачена.Эта функция основана на тегах Cloud Run , которые имеют ограничение в 1000 тегов на сервис и 2000 тегов на регион. Это означает, что после сотен развертываний самые старые версии сайта могут перестать работать.
После добавления этого правила перезаписи и развертывания в Firebase (с помощью firebase deploy ), образ вашего контейнера станет доступен по следующим URL-адресам:
Ваши поддомены Firebase:
PROJECT_ID .web.app/helloworldиPROJECT_ID .firebaseapp.com/helloworldЛюбые подключенные пользовательские домены :
CUSTOM_DOMAIN /helloworld
При перенаправлении запросов к контейнерам Cloud Run с использованием Hosting поддерживаются следующие методы HTTP-запросов: GET , POST , HEAD , PUT , DELETE , PATCH и OPTIONS . Другие методы, такие как REPORT или PROFIND не поддерживаются.
Для достижения наилучшей производительности разместите ваш сервис Cloud Run совместно с Hosting , используя следующие регионы:
-
us-west1 -
us-central1 -
us-east1 -
europe-west1 -
asia-east1
Переадресация запросов в Cloud Run с Hosting поддерживается в следующих регионах:
-
asia-east1 -
asia-east2 -
asia-northeast1 -
asia-northeast2 -
asia-northeast3 -
asia-south1 -
asia-south2 -
asia-southeast1 -
asia-southeast2 -
australia-southeast1 -
australia-southeast2 -
europe-central2 -
europe-north1 -
europe-southwest1 -
europe-west1 -
europe-west12 -
europe-west2 -
europe-west3 -
europe-west4 -
europe-west6 -
europe-west8 -
europe-west9 -
me-central1 -
me-west1 -
northamerica-northeast1 -
northamerica-northeast2 -
southamerica-east1 -
southamerica-west1 -
us-central1 -
us-east1 -
us-east4 -
us-east5 -
us-south1 -
us-west1 -
us-west2 -
us-west3 -
us-west4 -
us-west1 -
us-central1 -
us-east1 -
europe-west1 -
asia-east1
Создание пользовательских Dynamic Links для домена
Вы можете использовать rewrites для создания Dynamic Links для пользовательских доменов. Подробную информацию о настройке динамических ссылок для пользовательского Dynamic Links см. в документации Dynamic Links .
Используйте свой собственный домен только для Dynamic Links
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/" "dynamicLinks": true } ] }Укажите пользовательские префиксы путей домена для использования в Dynamic Links
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/promos/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/promos/" "dynamicLinks": true }, { "source": "/links/share/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/links/share/" "dynamicLinks": true } ] }
Для настройки Dynamic Links в файле firebase.json необходимо выполнить следующие действия:
| Поле | Описание | |
|---|---|---|
appAssociation | Необходимо установить значение
| |
rewrites | ||
source | Путь, который вы хотите использовать для Dynamic Links В отличие от правил, переписывающих пути к URL-адресам, правила перезаписи для Dynamic Links не могут содержать регулярные выражения. | |
dynamicLinks | Необходимо установить значение true | |
Настройка заголовков
Необязательный
Заголовки позволяют клиенту и серверу передавать дополнительную информацию вместе с запросом или ответом. Некоторые наборы заголовков могут влиять на то, как браузер обрабатывает страницу и ее содержимое, включая контроль доступа, аутентификацию, кэширование и кодирование.
Укажите пользовательские заголовки ответа, специфичные для файла, создав атрибут headers , содержащий массив объектов заголовков. В каждом объекте укажите шаблон URL, который, если он совпадает с путем URL-адреса запроса, запускает Hosting для применения указанных пользовательских заголовков ответа.
Вот базовая структура атрибута headers . В этом примере применяется заголовок CORS ко всем файлам шрифтов.
"hosting": {
// ...
// Applies a CORS header for all font files
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
} ]
}
"hosting": { // ... // Add the "headers" attribute within "hosting" "headers": [ { // Applies a CORS header for all font files "source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] }, { // Overrides the default 1 hour browser cache with a 2 hour cache for all image files "source": "**/*.@(jpg|jpeg|gif|png)", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // A regular expression-based rewrite equivalent to the above behavior "regex": ".+/\w+\.(jpg|jpeg|gif|png)$", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // Sets the cache header for 404 pages to cache for 5 minutes "source": "404.html", "headers": [ { "key": "Cache-Control", "value": "max-age=300" } ] } ] }
Атрибут headers содержит массив определений, причем каждое определение должно включать поля из приведенной ниже таблицы.
| Поле | Описание | ||
|---|---|---|---|
headers | |||
source (рекомендуется)или regex | Шаблон URL-адреса, который, если совпадает с исходным URL-адресом запроса, запускает процесс применения пользовательского заголовка Hosting
Чтобы создать заголовок, соответствующий вашей пользовательской странице 404 , используйте | ||
массив (под) headers | Пользовательские заголовки, которые Hosting применяет к пути запроса. Каждый подзаголовок должен содержать пару | ||
key | Название заголовка, например, Cache-Control | ||
value | Значение для заголовка, например, max-age=7200 | ||
Подробнее о Cache-Control можно узнать в разделе Hosting , где описывается обслуживание динамического контента и размещение микросервисов. Также вы можете узнать больше о заголовках CORS .
Управление расширениями .html
Необязательный
Атрибут cleanUrls позволяет управлять тем, должны ли URL-адреса включать расширение .html .
Если true , Hosting автоматически удаляет расширение .html из URL-адресов загружаемых файлов. Если же в запросе добавлено расширение .html , Hosting выполняет перенаправление 301 на тот же путь, но удаляет расширение .html .
Вот как можно контролировать включение .html в URL-адреса, добавив атрибут cleanUrls :
"hosting": {
// ...
// Drops `.html` from uploaded URLs
"cleanUrls": true
}
Контрольные косые черты в конце строки
Необязательный
Атрибут trailingSlash позволяет управлять тем, должны ли URL-адреса статического контента содержать завершающие косые черты.
- Если
true, Hosting перенаправляет URL-адреса, добавляя в конце косую черту. - Если
false, Hosting перенаправляет URL-адреса, удаляя завершающую косую черту. - Если не указано иное, Hosting использует косые черты в конце только для файлов индексов каталогов (например,
about/index.html).
Вот как можно управлять завершающими косыми чертами, добавив атрибут trailingSlash :
"hosting": {
// ...
// Removes trailing slashes from URLs
"trailingSlash": false
}
Атрибут trailingSlash не влияет на перезапись динамического контента, предоставляемого Cloud Functions или Cloud Run .
Сопоставление шаблонов Glob
В параметрах конфигурации Firebase Hosting широко используется обозначение сопоставления шаблонов glob с помощью extglob, аналогично тому, как Git обрабатывает правила gitignore , а Bower — правила ignore . Эта страница вики является более подробным справочником, но ниже приведены пояснения к примерам, используемым на этой странице:
firebase.json— Соответствует только файлуfirebase.json, находящемуся в корневом каталогеpublic**— Находит любой файл или папку в произвольной подпапке*— Соответствует только файлам и папкам в корневом каталогеpublic**/.*— Находит любой файл, начинающийся с.(обычно скрытые файлы, например, в папке.git), в произвольной подпапке.**/node_modules/**— Соответствует любому файлу или папке в произвольной подпапке папкиnode_modules, которая, в свою очередь, может находиться в произвольной подпапке каталогаpublic.**/*.@(jpg|jpeg|gif|png)— Находит любой файл в произвольной подпапке, который заканчивается ровно одним из следующих символов:.jpg,.jpeg,.gifили.png
Пример полной конфигурации Hosting
Ниже приведён полный пример конфигурации firebase.json для Firebase Hosting . Обратите внимание, что файл firebase.json также может содержать конфигурации для других сервисов Firebase .
{
"hosting": {
"public": "dist/app", // "public" is the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
"source": "/firebase/**",
"destination": "https://www.firebase.com",
"type": 302
} ],
"rewrites": [ {
// Shows the same content for multiple URLs
"source": "/app/**",
"destination": "/app/index.html"
}, {
// Configures a custom domain for Dynamic Links
"source": "/promos/**",
"dynamicLinks": true
}, {
// Directs a request to Cloud Functions
"source": "/bigben",
"function": "bigben"
}, {
// Directs a request to a Cloud Run containerized app
"source": "/helloworld",
"run": {
"serviceId": "helloworld",
"region": "us-central1"
}
} ],
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
}, {
"source": "**/*.@(jpg|jpeg|gif|png)",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=7200"
} ]
}, {
"source": "404.html",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=300"
} ]
} ],
"cleanUrls": true,
"trailingSlash": false,
// Required to configure custom domains for Dynamic Links
"appAssociation": "AUTO",
}
}