在同一URL下在S3 + Cloudfront上托管多个SPA Web应用程序

SRa*_*zzo 5 amazon-s3 amazon-web-services amazon-cloudfront single-page-application create-react-app

我有两个静态Web应用程序(create-react-apps),它们当前位于两个单独的S3存储桶中。将两个存储桶都配置为公共读取+静态Web托管,并且访问其S3托管URL会正确显示站点。

Bucket 1 - First App:
   index.html
   static/js/main.js

Bucket 2 - Second App:
   /secondapp/
       index.html
       static/js/main.js
Run Code Online (Sandbox Code Playgroud)

我为此设置了一个Cloudfront-默认正确地加载了默认Cloudfront源FirstApp,例如,默认情况下www.mywebsite.com加载了index.html。

对于SecondApp,我已经设置了“缓存行为”,以便路径模式secondapp/*指向SecondApp存储桶URL。

在我的浏览器中,当我访问www.mywebsite.com/secondapp/它时,它会正确显示第二个Web应用程序。

但是,如果省略斜杠,则会看到“ First App”,这是不希望的。如果我访问www.mywebsite.com/secondapp/something,还会看到我不希望看到的第一个应用程序。(我希望它加载的.html secondapp

两个应用程序都配置为通过react-router-dom使用html5推送状态。

我想要的行为是访问以下内容显示正确的站点/存储桶:

www.mywebsite.com - 正在工作

www.mywebsite.com/secondapp/ - 正在工作

www.mywebsite.com/secondapp -(不带斜杠)不起作用,显示第一个应用程序

www.mywebsite.com/secondapp/something_else -无法运作,显示第一个应用程式

我怎样才能达到预期的行为?

谢谢!

SRa*_*zzo 13

在研究了这个问题后,我能够使用 lambda@edge ( https://aws.amazon.com/lambda/edge/ )解决它

通过部署一个简单的 javascript 函数来将特定路径路由到所需的 s3 存储桶,我们能够实现类似 nginx 的路由设置。该函数位于我们 Cloudfront CDN 上的 lambda@edge 上,这意味着您可以指定何时触发它。对我们来说,它在“原始请求”上

我的设置如下:

  • 我使用了一个 s3 存储桶,并将我的第二个应用程序部署在子文件夹“second-app”中
  • 我创建了一个新的 Lambda 函数,托管在“US East N Virginia”上。该区域在这里很重要,因为您只能在该区域中托管 lambda 函数和 @edge。
  • 请参阅下面的实际 Lambda 函数
  • 创建后,转到您的 CloudFront 配置并转到“行为 > 选择默认 (*) 路径模式并点击编辑”
  • 滚动到底部有“Lambda 函数关联”的地方
  • 从下拉菜单中选择“Origin Request”
  • 输入 lambda 函数的地址 ( arn:aws:lambda:us-east-1:12345667890:function:my-function-name)

这是我使用的 lambda 函数的示例。


var path = require('path');

exports.handler = (event, context, callback) => {
  // Extract the request from the CloudFront event that is sent to Lambda@Edge
  var request = event.Records[0].cf.request;

  const parsedPath = path.parse(request.uri);

  // If there is no extension present, attempt to rewrite url
  if (parsedPath.ext === '') {
    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/second-app.*/, 'second-app/index.html');

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;
  }
  // If an extension was not present, we are trying to load static access, so allow the request to proceed
  // Return to CloudFront
  return callback(null, request);
};
Run Code Online (Sandbox Code Playgroud)

这些是我用于此解决方案的资源:

  • 他忽略了扩展的事情。 (2认同)