在管理缓存时使用 CloudFront 在 S3 上部署 React 应用程序的步骤?

Steps to deploy a React app on S3 with CloudFront while managing caching?

我需要使用 SSL 和管理缓存在 AWS S3 上部署 React 应用程序。需要哪些步骤,我可能会遇到哪些问题?

为什么要这样做?

它可以非常快,"serverless" 而且非常便宜。通过 CloudFront 全球端点(边缘位置),应用程序可以 运行 非常快速且具有高可靠性。通过设置另一个来源,CloudFront 可以充当 API 的反向代理,消除 cross-region (CORS) 问题并加速远程位置的 API 调用。可以将多个部署上传到单个 S3 存储桶。

基本概念

将 Create React App 部署到 S3/CloudFront:

时需要牢记许多概念
  • CloudFront 前端 - 对于自定义域,SSL 流量将通过 CloudFront 而不是 S3(不允许使用自定义域的 SSL)
  • 一对多 - 单个 S3 存储桶可以容纳多个部署(例如测试、生产)。我使用指向相同存储桶但不同前缀的专用 CloudFront 分配设置每个部署(例如 deployments/testing、deployments/production)
  • Cross-domain API 问题可以避免 - 有一种方法可以对 S3 中的静态文件和动态文件使用 CloudFront API, 都在同一个域中(见下文)
  • 压缩 - 应始终在 CloudFront 上启用压缩
  • 浏览器缓存 - CRA 构建将创建带有散列键的块文件。这些可以在浏览器中缓存很长时间。但是像 index.html 这样没有散列键的文件应该设置为 no-caching。这些缓存属性可以通过S3设置。

Cross-domain API 问题 (CORS) - 如何避免

每个 CloudFront 分配可以有多个来源。一个源应设置为 S3,而另一个可以设置为 API 服务器或负载平衡器。如果 API 服务器在 AWS 系统内,CloudFront 可以安全地使用 non-SSL(端口 80)作为代理服务器进行通信。

要使用端口 80,API 服务器必须配置为响应 non-secure 流量(如果流量仅为端口 80,则不需要 SSL 证书)。 Apache VirtualHost 将使用 CloudFront 实例的主机名 而不是 API 服务器主机名(例如 my.react-app.com 而不是 my.api.com),因为 HTTP 请求主机值为未修改。

要使用 CloudFront 启用 API:

  1. 将您的 API 服务器添加为来源,HTTP 仅当在 AWS 中时才如此
  2. 添加新行为,/api/* 路径模式,仅 HTTPS 查看器策略,所有 HTTP 方法(除非您只有 GET),ALL 基于选定请求的缓存Headers,已启用压缩 Objects,并且 转发所有查询字符串
  3. CloudFront 不应缓存任何内容(除非您可以这样做)

正在复制到 S3

将构建系统复制到 S3 的简单方法是:

aws s3 sync . s3://MY-S3-BUCKET/ --quiet

这是非常有限的。它不会轻易管理浏览器缓存。可以删除旧文件(--delete 选项)或保留(默认);当然,这个工具不知道哪些 CRA 文件 应该 为旧版本维护,所以垃圾 collection 会很复杂。

Python 将 CRA 部署到 S3 / CloudFront 的工具

我构建了 a python tool 它将:

  1. 将任何新文件上传到 S3,将 Etag 验证为 MD5
  2. 删除所有旧文件
  3. 可选择维护属于早期版本的旧文件(下载和解析旧 precache-manifest 文件)
  4. 为不同的文件设置 HTTP 缓存参数(即缓存带散列键的文件,普通文件不缓存)
  5. 清除 CloudFront 分配(即失效请求)

即使您不使用它,它也可以帮助您解决部署系统问题。

在 CloudFront 中启用 React Router

要在 React Router 中启用不同的路径,set the the CloudFront error page/index.html(这样所有失败的请求都会到达那里):

  1. 转到 AWS 控制台中的 CloudFront 分配
  2. 单击相应的 CloudFront 分配
  3. 单击“错误页面”选项卡
  4. 403: Forbidden404: Not Found 指向添加错误响应 /index.html HTTP 响应 200

测试 HTTP headers

如果您的 S3 存储桶设置为静态网站托管,您可以查看此 HTTP header(注意 CloudFront 工作不需要 S3 网站托管):

curl -I http://MY-S3-ENDPOINT/index.html

同样,您可以从 CloudFront 测试 header:

curl -I https://CLOUDFRONT-URL/index.html

要测试压缩,请将编码接受添加到请求 HTTP header,例如

curl -H "Accept-Encoding: gzip" -I https://CLOUDFRONT-URL/index.html

很好的问答 @charlie-hileman,感谢分享! 关于“我可能遇到的一些问题”,我正在探索这种方法的相关 成本,我认为它可能会帮助其他人解决这个问题。

CloudFront 文档:

No additional charge for the first 1,000 paths requested for invalidation each month. Thereafter, [=13=].005 per path requested for invalidation.

简单的公式,但在没有实际项目的情况下很难分解。

公式:

0.005 * ((files * deployments) - 1000)

我的 create-react-app 生成了 202 个文件(由于默认的分块策略,其中很多是 webpack 块)。为了便于数学计算,我会将其四舍五入为 200。这意味着我每月大约可以免费获得五次失效:

0.005 * ((200 * 5) - 1000)      // [=11=].00

除此之外,每次部署的费用为 1 美元。

让我们扩展一下。假设我一个月大约工作 20 天(每周 5 天,平均每月 4 周)。按照这个速度,如果我平均部署 1 天、2 天、3 天...

0.005 * ((200 * 20 * 1) - 1000) // /mo
                   * 2          // /mo
                   * 3          // /mo
                   * 4          // /mo
                   * 5          // /mo

考虑到好处,这实际上仍然相对经济,现在我要了解成本。另外,如果项目随着时间的推移稳定下来并且部署更少,这可能是摊销成本。我会将此与(例如)保持节点服务器运行以托管此项目的比较运营成本相比较。