配置托管行为

通过 Firebase 托管,您可以配置自定义托管行为,包括自定义错误页面重定向重写标头。您还可以指定要将哪些文件从您的项目目录部署到 Firebase 项目

firebase.json 文件中定义您的 Firebase 托管配置。

在项目的根目录中找到您的 firebase.json 文件。当您运行 firebase init 命令时,Firebase 会自动创建 firebase.json 文件。

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

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

托管响应的优先级顺序

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

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

指定要部署的文件

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

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

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

公开

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

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

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

  // ...
}

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

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

  // ...
}

ignore

可选
ignore 属性指定在部署时要忽略的文件。它可以处理 glob,所采用的方式与 Git 处理 .gitignore 的方式一样。

以下是要忽略的文件的默认值:

"hosting": {
  // ...

  "ignore": [
    "firebase.json",  // the Firebase configuration file (this file)
    "**/.*",  // 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/Not Found 页面

可选
当用户尝试访问的页面不存在时,您可以显示自定义 404 Not Found 错误。

在项目的 public 目录中创建一个新文件,将其命名为 404.html,然后在该文件中添加自定义的 404 Not Found 内容。

如果浏览器在您的网域或子网域上触发 404 Not Found 错误,Firebase 托管将显示该自定义 404.html 页面的内容。

配置重定向

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

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

以下是 redirects 属性示例:

"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 属性包含一系列重定向规则,其中每条规则都必须包含以下字段:

  • sourceregex - 指定一个网址格式,如果该格式与请求网址匹配,便触发托管应用重定向

  • destination - 指定可以是相对路径或绝对路径的静态网址

  • type - 指定 HTTP 响应代码

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

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

捕获重定向的网址段

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

在使用 glob 时捕获网址段

如果您使用的是 source 字段(即为您的网址格式指定 glob),则可以通过添加 : 前缀来标识该网址段,从而加以捕获。如果您还需要捕获网址段后面的其余网址路径,请紧接网址段后面添加一个 *。例如:

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

在使用 RE2 正则表达式时捕获网址段

如果您使用的是 regex 字段(即为您的网址格式指定 RE2 正则表达式),则可以使用已命名或未命名的 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
  } ]
}

配置重写

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

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

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

以下是 rewrites 属性示例:

"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 属性包含一系列重写规则,其中每条规则都必须包含以下字段:

  • sourceregex - 指定一个网址格式,如果该格式与请求网址匹配,则会触发托管应用重写

  • destination - 指定必须存在的本地文件

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

将请求定向到函数

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

例如,如需定向来自您托管网站上 /bigben 页面的所有请求以执行 bigben 函数,请使用以下代码:

"hosting": {
  // ...

  // Add the "rewrites" attribute within "hosting"
  "rewrites": [ {
    "source": "/bigben",
    "function": "bigben"
  } ]
}

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

  • 您的 Firebase 子网域:projectID.web.app/bigbenprojectID.firebaseapp.com/bigben

  • 任何关联的自定义网域custom-domain/bigben

将请求定向到 Cloud Run 容器

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

例如,如需定向来自您托管网站上 /helloworld 页面的所有请求以触发 helloworld 容器实例的启动和运行,请使用以下代码:

"hosting": {
 // ...

 // Add the "rewrites" attribute within "hosting"
 "rewrites": [ {
   "source": "/helloworld",
   "run": {
     "serviceId": "helloworld",  // "service name" (from when you <a href="#deploy">deployed the container image)</a>
     "region": "us-central1"     // optional (if omitted, default is us-central1)
   }
 } ]
}

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

  • 您的 Firebase 子网域:projectID.web.app/helloworldprojectID.firebaseapp.com/helloworld

  • 任何关联的自定义网域custom-domain/helloworld

您可以使用 rewrites 创建自定义网域动态链接。如需详细了解如何为动态链接设置自定义网域,请参阅动态链接文档。

例如,您可以执行以下操作:

  • 将您的网域仅用于动态链接:

    "hosting": {
      // ...
    
      "appAssociation": "AUTO",  // required for Dynamic Links (default is AUTO if not specified)
    
      // Add the "rewrites" attribute within "hosting"
      "rewrites": [ {
        "source": "/**",  // Dynamic Links start with "https://<your-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/**",  // Dynamic Links can start with "https://<your-domain>/promos/"
        "dynamicLinks": true
      }, {
        "source": "/links/share/**",  // Dynamic Links can start with "https://<your-domain>/links/share/"
        "dynamicLinks": true
      } ]
    }
    

firebase.json 文件中配置动态链接需要进行如下设置:

  • appAssociation 属性设置为 AUTO

    • 如果您的配置中不包含该特性,则 appAssociation 的默认值为 AUTO
    • 将该特性设置为 AUTO 后,托管会在收到相应请求时动态生成 assetlinks.jsonapple-app-site-association 文件。
  • 动态链接的 rewrites 特性,包含一系列重写规则,其中每条规则必须包含以下各项:

    • source,指定要用于动态链接的路径

      • 与将路径重写为网址的规则不同,动态链接重写规则不能包含正则表达式。
    • dynamicLinks 特性设置为 true

配置标头

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

通过创建包含一系列标头对象的 headers 属性来指定文件专属的自定义响应标头。在每个对象中,指定一个网址格式,如果该格式与请求网址路径匹配,便触发托管应用指定的自定义响应标头。

以下是 headers 属性示例:

"hosting": {
  // ...

  // Add the "headers" attribute within "hosting"
  "headers": [ {
    // Specifies 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 属性包含一系列定义,其中每个定义都必须包含以下字段:

  • sourceregex - 指定一个网址格式,如果该格式与请求网址匹配,则会触发托管应用自定义标头

  • 一系列(子)headers - 指定托管应用于请求路径的自定义标头。每个子标头数组都必须包含一个指定的 key 和一个 value

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

您还可以详细了解 CORS 标头。

控制 .html 扩展名

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

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

通过在 firebase.json 文件的 hosting 中添加一个 cleanUrls 特性,指定包含 .html 扩展名。例如:

"hosting": {
  // ...

  // Add the "cleanUrls" attribute within "hosting"
  "cleanUrls": true
}

控制尾随斜杠

可选
通过 trailingSlash 特性,您可以控制网址是否应包含尾随斜杠。

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

通过在 firebase.json 文件的 hosting 中添加一个 trailingSlash 特性,即可指定要包含尾随斜杠。例如:

"hosting": {
  // ...

  // Add the "trailingSlash" attribute within "hosting"
  "trailingSlash": false
}

Glob 模式匹配

Firebase 托管配置选项通过 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 结尾的任何文件

完整的托管配置示例

以下是 Firebase 托管的完整 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",

  }
}