配置 Hosting 行为

借助 Firebase Hosting,您可以为网站请求配置自定义托管行为。

可以为 Hosting 配置哪些内容?

  • 在本地项目目录中指定要部署到 Firebase Hosting 的文件。了解具体方法

  • 提供自定义的“404/未找到”页面。了解具体方法

  • 为您已移动或已删除的页面设置 redirects了解具体方法

  • 为以下目的设置 rewrites

  • 添加 headers 以传递有关请求或响应的额外信息,例如浏览器应如何处理页面及其内容(身份验证、缓存、编码等等)。了解具体方法

  • 设置国际化 (i18n) 重写以根据用户的语言偏好和/或国家/地区提供特定内容。了解具体方法(不同页面)。

在何处定义 Hosting 配置?

可以在 firebase.json 文件中定义 Firebase Hosting 配置。当您运行 firebase init 命令时,Firebase 会自动在项目的根目录中创建 firebase.json 文件。

您可以在本页底部找到完整的 firebase.json 配置示例(仅涵盖 Firebase Hosting)。请注意,firebase.json 文件也可以包含其他 Firebase 服务的配置

您可以使用 Hosting REST API 检查已部署的 firebase.json 内容。

Hosting 响应的优先级顺序

本页介绍的不同 Firebase Hosting 配置选项有时可能会重叠。如果有冲突,Hosting 会按照以下优先级顺序确定应如何响应:

  1. /__/* 路径段开头的预留命名空间
  2. 配置的重定向
  3. 完全匹配的静态内容
  4. 配置的重写
  5. 自定义 404 页面
  6. 默认的 404 页面

如果使用 i18n 重写,则完全匹配和 404 处理优先级顺序会在范围内扩展,以适应“i18n content”。

指定要部署的文件

默认 firebase.json 文件中包含的默认属性 publicignore 定义了应将项目目录中的哪些文件部署到您的 Firebase 项目。

firebase.json 文件中的默认 hosting 配置如下所示:

"hosting": {
  "public": "public",  // the only required attribute for Hosting
  "ignore": [
    "firebase.json",
    "**/.*",
    "**/node_modules/**"
  ]
}

public

必需
public 属性指定要部署到 Firebase Hosting 的目录。默认值是名为 public 的目录,但您可以指定任何目录的路径,只要项目目录中存在该路径即可。

以下是要部署的目录的默认指定名称:

"hosting": {
  "public": "public"

  // ...
}

您可以将默认值更改为您想要部署的目录:

"hosting": {
  "public": "dist/app"

  // ...
}

ignore

可选
ignore 属性指定在部署时要忽略的文件。它可以使用 glob,与 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 页面的内容。

配置重定向

可选
使用网址重定向可防止在页面转移后出现损坏的链接,还可以缩短网址。例如,您可以将浏览器从 example.com/team 重定向至 example.com/about.html

通过创建包含一系列对象(称为“重定向规则”)的 redirects 属性来指定网址重定向。在每条规则中指定一个网址格式,如果该网址格式与请求网址路径相匹配,则会触发 Hosting 做出重定向到指定目标网址的响应。

以下是 redirects 属性的基本结构。此示例通过向 /bar 发出新请求来将请求重定向到 /foo

"hosting": {
  // ...

  // Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
  "redirects": [ {
    "source": "/foo",
    "destination": "/bar",
    "type": 301
  } ]
}

redirects 属性包含一系列重定向规则,其中每条规则都必须包含下表中的字段。

Firebase Hosting 会在开始处理每个请求时(在浏览器确定该路径中是否存在文件或文件夹之前),将 sourceregex 值与所有网址路径进行比较。如果找到匹配项,Firebase Hosting 源服务器会发送 HTTPS 重定向响应,告知浏览器向 destination 网址发出新请求。

字段 说明
redirects
source(推荐)
regex

一个网址格式,如果该格式与初始请求网址匹配,则会触发 Hosting 应用重定向

destination

浏览器应向其发出新请求的静态网址

此网址可以是相对路径,也可以是绝对路径。

type

HTTPS 响应代码

  • 使用 301 类型表示“永久移动”
  • 使用 302 类型表示“发现”(临时重定向)

捕获重定向的网址段

可选
有时,您可能需要捕获重定向规则网址格式(sourceregex 值)的特定网址段,然后在该规则的 destination 路径中重复使用这些网址段。

配置重写

可选
使用重写可以为多个网址显示相同的内容。重写在与模式匹配结合使用时尤其有用,因为您可以接受与模式匹配的任何网址,让客户端代码来决定要显示的内容。

您还可以使用重写来支持使用 HTML5 pushState 进行导航的应用。当某浏览器尝试打开与指定的 sourceregex 网址格式匹配的网址路径时,浏览器会改为获取 destination 网址中文件的内容。

通过创建包含一系列对象(称为“重写规则”)的 rewrites 属性来指定网址重写。在每条规则中指定一个网址格式,如果该网址格式与请求网址路径相匹配,则会触发 Hosting 进行响应,其行为就像是已为服务提供了指定的目标网址。

以下是 rewrites 属性的基本结构。此示例为访问不存在的文件或目录的请求提供 index.html

"hosting": {
  // ...

  // Serves index.html for requests to files or directories that do not exist
  "rewrites": [ {
    "source": "**",
    "destination": "/index.html"
  } ]
}

rewrites 属性包含一系列重写规则,其中每条规则都必须包含下表中的字段。

仅当与指定的 sourceregex 网址格式匹配的网址路径中不存在文件或目录时,Firebase Hosting 才会采用重写规则。当请求触发重写规则时,浏览器会返回指定 destination 文件的实际内容,而不是 HTTP 重定向。

字段 说明
rewrites
source(推荐)
regex

一个网址格式,如果该格式与初始请求网址匹配,则会触发 Hosting 采用重写

destination

必须存在的本地文件

此网址可以是相对路径,也可以是绝对路径。

将请求定向到函数

您可以使用 rewrites 从 Firebase Hosting 网址提供函数。以下示例摘自使用 Cloud Functions 提供动态内容

例如,如需定向来自您的 Hosting 网站上 /bigben 页面的所有请求以执行 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)
    }
  } ]
}

添加此重写规则并部署到 Firebase(使用 firebase deploy)后,便可通过以下网址访问您的函数:

  • 您的 Firebase 子网域:
    PROJECT_ID.web.app/bigbenPROJECT_ID.firebaseapp.com/bigben

  • 任何关联的自定义网域
    CUSTOM_DOMAIN/bigben

使用 Hosting 将请求重定向到函数时,支持的 HTTP 请求方法有:GETPOSTHEADPUTDELETEPATCHOPTIONS。不支持 REPORTPROFIND 等其他方法。

将请求定向到 Cloud Run 容器

您可以使用 rewrites 从 Firebase Hosting 网址访问 Cloud Run 容器。以下示例摘自使用 Cloud Run 提供动态内容

例如,如需定向来自您 Hosting 网站上 /helloworld 页面的所有请求以触发 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)
   }
 } ]
}

添加此重写规则并部署到 Firebase(使用 firebase deploy)后,便可通过以下网址访问您的容器映像:

  • 您的 Firebase 子网域:
    PROJECT_ID.web.app/helloworldPROJECT_ID.firebaseapp.com/helloworld

  • 任何关联的自定义网域
    CUSTOM_DOMAIN/helloworld

使用 Hosting 将请求重定向到 Cloud Run 容器时,支持的 HTTP 请求方法有:GETPOSTHEADPUTDELETEPATCHOPTIONS。不支持 REPORTPROFIND 等其他方法。

为获得最佳性能,请使用以下区域将您的 Cloud Run 服务与 Hosting 共置:

  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

以下区域支持从 Hosting 重写到 Cloud Run:

  • 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

您可以使用 rewrites 创建自定义网域动态链接。如需详细了解如何为动态链接设置自定义网域,请参阅 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
      } ]
    }
    
  • 指定要用于动态链接的自定义网域的路径前缀

    "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
      } ]
    }
    

firebase.json 文件中配置 Dynamic Links 需要进行如下设置:

字段 说明
appAssociation

必须设置为 AUTO

  • 如果您未在配置中添加此属性,则 appAssociation 的默认值为 AUTO
  • 通过将此属性设置为 AUTO,Hosting 可以在收到相应请求时动态生成 assetlinks.jsonapple-app-site-association 文件。
rewrites
source

要用于 Dynamic Links 的路径

与重写网址路径的规则不同,动态链接的重写规则不能包含正则表达式。

dynamicLinks 必须设置为 true

配置标头

可选
通过标头,客户端和服务器可以将其他信息连同请求或响应一起传递。一些标头集可能会影响浏览器处理页面及其内容的方式,包括访问权限控制、身份验证、缓存和编码。

通过创建包含一系列标头对象的 headers 属性来指定文件专属的自定义响应标头。在每个对象中,指定一个网址格式,如果该格式与请求网址路径匹配,便触发 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": "*"
    } ]
  } ]
}

headers 属性包含一系列定义,其中每个定义都必须包含下表中的字段。

字段 说明
headers
source(推荐)
regex

一个网址格式,如果该格式与初始请求网址匹配,则会触发 Hosting 应用自定义标头

如需创建与您的自定义 404 页面匹配的标头,请使用 404.html 作为您的 sourceregex 值。

一系列(子)headers

Hosting 应用于请求路径的自定义标头

每个子标头都必须包含一个 key-value(请参阅下面两行)。

key 标头的名称,例如 Cache-Control
value 标头的值,例如 max-age=7200

如需详细了解 Cache-Control,请参阅介绍如何提供动态内容和托管微服务的“Hosting”部分。您还可以详细了解 CORS 标头。

控制 .html 扩展名

可选
通过 cleanUrls 属性,您可以控制网址是否应包含 .html 扩展名。

如果值为 true,Hosting 会从已上传的文件网址中自动删除 .html 扩展名。如果在请求中添加 .html 扩展名,Hosting 会执行 301 重定向,以重定向至相同路径,但会删除 .html 扩展名。

以下是通过添加 cleanUrls 属性来控制在网址中包含 .html 的方法:

"hosting": {
  // ...

  // Drops `.html` from uploaded URLs
  "cleanUrls": true
}

控制尾随斜杠

可选
trailingSlash 属性可让您控制静态内容网址是否应包含结尾斜杠。

  • 如果值为 true,Hosting 会重定向网址以添加尾随斜杠。
  • 如果值为 false,Hosting 会重定向网址以移除尾随斜杠。
  • 如果不指定,Hosting 将仅对目录索引文件(例如 about/index.html)使用尾随斜杠。

以下是通过添加 trailingSlash 属性来控制尾随斜杠的方法:

"hosting": {
  // ...

  // Removes trailing slashes from URLs
  "trailingSlash": false
}

trailingSlash 属性不会影响对 Cloud Functions 或 Cloud Run 提供的动态内容的重写。

Glob 模式匹配

Firebase Hosting 配置选项通过 extglob 广泛使用了 glob 模式匹配表示法,其方式与 Git 处理 gitignore 规则以及 Bower 处理 ignore 规则的方式类似。此 Wiki 页提供了更加详细的参考。以下是对此页面中使用的示例的说明:

  • firebase.json - 仅与 public 目录的根目录下的 firebase.json 文件匹配

  • ** - 与任意子目录中的任何文件或文件夹匹配

  • * - 仅与 public 目录的根目录下的文件和文件夹匹配

  • **/.* - 匹配任意子目录中以 . 开头的任何文件(通常是隐藏文件,例如 .git 文件夹中的文件)

  • **/node_modules/** - 匹配 node_modules 文件夹(该文件夹本身可以位于 public 目录的任意子目录中)的任意子目录中的任何文件或文件夹

  • **/*.@(jpg|jpeg|gif|png) - 匹配任意子目录中以 .jpg.jpeg.gif.png 结尾的任何文件

完整的 Hosting 配置示例

以下是 Firebase Hosting 的完整 firebase.json 配置示例。请注意,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",

  }
}