Firebase 托管:如何防止缓存 SPA 的 index.html

Firebase hosting: How to prevent caching for the index.html of an SPA

我在 firebase 上托管一个 SPA,其中几乎所有路径都被重写为 index.html。我正在使用基于 webpack 散列的缓存破坏,所以我想始终阻止缓存我的 index.html 而不是任何其他文件。我发现这样做出奇地困难。具体来说,我的文件布局如下所示

/
├── index.html
├── login.html
├── js
│   ├── login.ba22ef2579d744b26c65.bundle.js
│   └── main.6d0ef60e45ae7a11063c.bundle.js
└── public
    └── favicon-16x16.ico

在阅读文档中的这句话之前,我天真地开始使用 "sources": "index.html"

Each definition must have a source key that is matched against the original request path regardless of any rewrite rules using glob notation.

好的,所以我想我需要一个路径,而不是一个简单的 glob 来指定我想要这些 headers 的文件。由于大多数路径重定向到 index.html,我需要一个 glob 来排除我不想将这些 headers 放在上面的所有路径。

作为参考,我的 firebase.json 托管部分如下所示:

{
  "hosting": {
    "public": "dist",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "cleanUrls": true,
    "trailingSlash": false,
    "headers": [
      {
        "source": <<<WHAT-GOES-HERE?>>>,
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache, no-store, must-revalidate"
          },
          {
            "key": "Pragma",
            "value": "no-cache"
          },
          {
            "key": "Expires",
            "value": "0"
          }
        ]
      }
    ]
  }
}

因此,举一些重定向到 index.html 且不应缓存的示例

mysite.com  
mysite.com/  
mysite.com/foo/bar/baz  
mysite.com/index.html 

注意:如果最后一个被缓存了,我还能活下去,因为它在实践中没有被使用。

不重定向到 index.html 且不应缓存的内容

**/*.* (ideally excluding index.html)
mysite.com/login  

我自己得到的最接近的是 **/!(login|*.*),它几乎适用于上面列出的所有内容,但莫名其妙地不适用于 mysite.commysite.com/。这 2 页与此 glob 不匹配,我不明白为什么。

这是我正在使用的配置。逻辑是对所有静态文件使用缓存,如 images, css, js 等。对于所有其他文件,即 "source": "/**" 将缓存设置为无缓存。因此对于所有其他文件,可能 example.com、example.com/index.html、example.com/about-us、example.com/about-us.html缓存将不会被应用。

{
  "hosting": {
    "public": "dist",
    "headers": [
      {
        "source": "/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache, no-store, must-revalidate"
          }
        ]
      },
      {
        "source":
          "**/*.@(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=604800"
          }
        ]
      }
    ],
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
  }
}

如果您的应用程序还包含一个服务工作者,请谨慎配置(我们在 firebase 组织中升级了一个 P1 问题,这就是我们所发现的)。您需要确保服务工作者未被缓存,并且 firebase 托管使用“最后规则获胜”工作,因此您需要确保您的服务工作者规则是最后的。喜欢这样的东西:

{
  "hosting": {
    "public": "dist",
    "headers": [
      {
        "source":
          "**/*.@(jpg|jpeg|gif|png|svg|webp|js|css|eot|otf|ttf|ttc|woff|woff2|font.css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=604800"
          }
        ]
      },
      {
        "source": "/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache, no-store, must-revalidate"
          }
        ]
      },
      {
        "source": "/service-worker.js",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache, no-store, must-revalidate"
          }
        ]
      }
    ],
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
  }
}

特别是因为你的 service worker 可能会 pre-caching,所以即使你的 index.html 不会在 CDN 级别缓存,并且 HTTP 请求会得到一个新的副本,pre-caching 的服务工作者,你可能仍然服务于 index.html

的旧副本

我最近也 运行 研究了这个问题,发现使用 /**/!(*.*) 的源 glob 效果很好,因为它将针对结尾不包含 [=12] 的任何子目录=],这实际上意味着它只会匹配路由(即 //login/account/edit 等)。然后我不需要为每个特定的文件扩展名编写排除项。

我希望这对某人有所帮助(并使您的配置更加合理)!

{
  "hosting": {
    "public": "build",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "headers": [
      {
        "source": "/**/!(*.*)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "no-cache"
          }
        ]
      },
      {
        "source": "**/*.chunk.@(js|css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=31536000, immutable"
          }
        ]
      }
    ]
  }
}

另请注意,我只是积极地缓存 JS 和 CSS 文件,其中包含 .chunk.(对于 OP,这应该更改为 .bundle.)。