在所有 aws 服务中,为 single-page-application 服务 index.html 的最高效方式是什么?

What is the most performant way to serve index.html for a single-page-application among all aws services?

试图找到在 AWS 中为单页应用程序提供 index.html 文件的最高效方式。主要要求是:

  1. AWS 服务必须能够提供来自 *.domain.com.
  2. 等通配符域的文件
  3. SPA 宁愿不使用 hash-based 路由,这意味着 https://foo.domain.com/path/to/resource 优于 URL,例如 https://foo.domain.com/#/path/to/resource

直接从 lambda-backed API 网关提供文件似乎不可行,因为该方法不满足自定义通配符域要求。

我们已经尝试 "unsuccessfully" 使用由 S3 源支持的云端。要将 SPA 与云端和 HTML5(非 hash-based)路径路由一起使用,您必须指定 CustomErrorResponses 为 http 状态代码 404 提供 index.html 文件和 403。虽然这可以正确地提供 index.html 文件,但响应总是以 x-cache: Error from cloudfront header 结束。这意味着在将 index.html 作为默认错误文档提供服务之前,cloudfront 需要时间在 S3 源中查找 HTML5 路径。将此与云端使用 origin-response Lambda@Edge 函数添加自定义 http headers 的事实相结合,会增加这些 non-cached 响应的延迟。

在美国的某些地区,我们发现对此文件的请求需要 500-1000 毫秒。例如,对于在弗吉尼亚托管的云前端分发和美国中部的查看器,请求似乎从查看器路由到最近的边缘位置(有时更靠西),然后往返于弗吉尼亚(托管 S3 源的地方) ,然后最终从边缘位置返回到查看器。

我们还尝试使用 Lambda@Edge 来缓存错误响应 body 以及 header,但均未成功。

我们还没有尝试过的是:

  1. Application Load Balancer 指向一个 lambda 函数(有或没有 API 网关)
  2. Application Load Balancer 直接指向 EC2 实例。

在我们决定尝试这些更昂贵的托管选项之前,询问社区是否有一种方法可以根据我们的要求提高云端的性能。如果不是,我预计 EC2 有可能比 ALB/lambda 性能更高,因为 EC2 不应该遭受冷启动?这是一个准确的假设吗?

对此的解决方案是让云端分发定义除 DefaultCacheBehavior (*) 之外的其他缓存行为。

使用 origin-request lambda@edge 关联设置默认缓存行为。当调用 origin-request 关联时,它应该 return 包含 index.html 文件内容以及任何必需的 header 的响应。此响应将缓存在任何请求的虚拟路径的分发中。 lambda@edge函数获取这些内容有两种方式:

  1. 在函数代码中,调用云端 index.html 文件的 http(s) 获取 URL(例如 dklyksfhsksdgjh.cloudfront.net/index.html).分发将 return 文件基于不同的 non-default 缓存行为,您也将设置该行为。这种方法在第一次请求任何虚拟 html5 路径时提供的性能不是最佳的,尽管后续请求将从云端分发缓存中提供内容。

  2. 在函数的构建过程中将 index.html 文件的内容嵌入到 lambda@edge 函数代码中。这种方法比选项 #1 提供更好的性能,因为不需要网络请求来获取文件内容。

使用 origin-response lambda@edge 关联为路径模式 /index.html 另外设置另一个缓存行为。当调用 origin-response 关联时,它应该将任何必需的 header 添加到响应中。

如果发行版包含其他文件(例如 /robots.txt、/favicon.ico、/fonts、/scripts、/styles 等),请设置与这些路径匹配的其他缓存行为。这是必需的,以便在默认缓存行为的 origin-request lambda@edge 关联期间,对这些文件的请求不会 return index.html 文件。

使用这种方法,对应用程序根目录的请求(即 www.site.com 或 www.site.com/index.html)将匹配 /index.html 缓存行为,从其 S3 来源获取文件,通过 origin-response lambda@edge 关联添加任何所需的 headers,并缓存文件。第一个请求应包含 x-cache: Miss from cloudfront 响应 header,但后续请求应 return x-cache: Hit from cloudfront 直到缓存 TTL 过期。

对其他文件的请求(例如 /robots.txt、/scripts/myscript.js 等)将匹配您为分发中的其他文件路径定义的其他缓存行为。

虚拟 HTML5 路径请求(即 www.site.com/path/handled/by/javascript)将匹配默认缓存行为,并且由于 origin-request lambda@edge 关联,return index.html 而不检查 S3 源中的任何文件。您仍然需要添加任何必需的 headers,就像 origin-response lambda@edge 关联对 /index.html 缓存行为所做的那样。请求将被缓存,尽管每个虚拟 HTML5 路径将被单独缓存。例如,对 /foo 的请求和对 /bar 的请求都将在缓存之前调用 origin-request lambda@edge 关联。