简体   繁体   English

重定向到 S3 子文件夹的 index.html

[英]Redirect to index.html for S3 subfolder

I have a domain example.com .我有一个域example.com I have a S3 bucket named example.com setup with an index.html file that works.我有一个名为example.com的 S3 存储桶设置,其中包含一个可用的index.html文件。 Now I like to create two subfolders called old and new , each containing a separate version of a single page application.现在我想创建两个名为oldnew的子文件夹,每个子文件夹包含一个单独版本的单页应用程序。 Requesting https://example.com/old (I like to omit the index.html when entering the request in address bar for browser) would open the index.html file in the old subfolder and requesting https://example.com/new would open the index.html .请求https://example.com/old (我喜欢在浏览器的地址栏中输入请求时省略index.html )将打开old子文件夹中的index.html文件并请求https://example.com/new将打开index.html What is the best way of doing these redirects?执行这些重定向的最佳方法是什么? Should I set something up in Route 53 example.com/old -> example.com/old/index.html or is there a better way of doing it?我应该在 Route 53 example.com/old -> example.com/old/index.html中设置一些东西还是有更好的方法?

No need for a lambda function adding expense and complexity to your project.不需要 lambda 函数来增加项目的费用和复杂性。

The following answer is quoted from https://stevepapa.com/以下答案引用自https://stevepapa.com/

https://stevepapa.com/my-great-new-post/ would be expected to work the same way as: https://stevepapa.com/my-great-new-post/index.html https://stevepapa.com/my-great-new-post/预计将以与以下方式相同的方式工作: https://stevepapa.com/my-great-new-post/index.html

There's a clever little way to get these flowing through to the Cloudfront distribution, and it involves changing the source origin from the one that Cloudfront presents to you by default.有一个聪明的小方法可以让这些流向 Cloudfront 分发,它涉及更改 Cloudfront 默认显示给您的来源。

When selecting the origin source Cloudfront will show you a list of S3 buckets.选择原始来源时,Cloudfront 将向您显示 S3 存储桶列表。 编辑原点

Instead of setting the source from the bucket shown in the dropdown list, you'll need to grab the static web hosting endpoint for that resource from its S3 settings page and pop it in manually.您无需从下拉列表中显示的存储桶中设置源,而是需要从其 S3 设置页面中获取该资源的静态 Web 托管端点并手动将其弹出。 静态托管端点 url 在哪里

Using the static source for the Cloudfront distribution origin means any request to that distribution will be using the S3's root object lookup, and your 404 responses should disappear as the references flow through.对 Cloudfront 分发源使用静态源意味着对该分发的任何请求都将使用 S3 的根对象查找,并且您的 404 响应应该随着引用流过而消失。

Important重要的

After doing this:这样做之后:

Otherwise, the changes you made won't go live immediately.否则,您所做的更改不会立即生效。

So I had this problem last night too.所以我昨晚也遇到了这个问题。

The issue is as follows: S3 when configured as a website bucket is forgiving and has the index document setting, set to index.html and this gets applied at the root, ie, example.com actually gets redirected to example.com/index.html , and it also gets applied at the subfolder level, so example.com/new or example.com/new/ should both redirect to example.com/new/index.html , where there would be an object in the bucket.问题如下:当配置为网站存储桶时,S3 是宽容的并且具有索引文档设置,设置为index.html并且这在根目录中应用,即example.com实际上被重定向到example.com/index.html ,它也会在子文件夹级别应用,因此example.com/newexample.com/new/都应该重定向到example.com/new/index.html ,存储桶中会有一个对象。 (If not, you'd get a NoSuchKey error instead.) (否则,您会收到NoSuchKey错误。)

However you then "upgrade" yourself to CloudFront, likely for HTTPS, and this feature goes away.然而,您随后将自己“升级”到 CloudFront,可能是为了 HTTPS,并且此功能消失了。 CloudFront instead makes explicit API calls to S3 and therefore doesn't trigger the index document concession. CloudFront 改为对 S3 进行显式 API 调用,因此不会触发索引文档让步。 It does work for the root, but not for subfolders.它确实适用于根目录,但不适用于子文件夹。

The RoutingRules solution doesn't look clean to me because by specifying KeyPrefixEquals rather than key exactly equals (which doesn't exist) I think you'd get unintended matches. RoutingRules解决方案在我看来并不干净,因为通过指定KeyPrefixEquals而不是 key exactly equals(不存在)我认为你会得到意想不到的匹配。

I instead have implemented a Lambda@Edge rule that rewrites the request that CloudFront makes to S3 to have a proper key value in it.相反,我实施了一个 Lambda@Edge 规则,该规则重写 CloudFront 向 S3 发出的请求以在其中具有适当的键值。

Start with the Lambda docs and the A/B testing example here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-general-examples从此处的 Lambda 文档和 A/B 测试示例开始: https ://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-general-examples

Change the code to:将代码更改为:

'use strict';

exports.handler = (event, context, callback) => {
    /*
     * Expand S3 request to have index.html if it ends in /
     */
    const request = event.Records[0].cf.request;
    if ((request.uri !== "/") /* Not the root object, which redirects properly */
        && (request.uri.endsWith("/") /* Folder with slash */
            || (request.uri.lastIndexOf(".") < request.uri.lastIndexOf("/")) /* Most likely a folder, it has no extension (heuristic) */
            )) {
        if (request.uri.endsWith("/"))
            request.uri = request.uri.concat("index.html");
        else
            request.uri = request.uri.concat("/index.html");
    }
    callback(null, request);
};

And publish it to your CloudFront distribution.并将其发布到您的 CloudFront 发行版。

There is even easier way to accomplish this with an HTML redirect file使用 HTML 重定向文件可以更简单地完成此操作

  1. Create a plain file named my-great-new-post (don't worry there won't be a name conflict with the folder in the same bucket)创建一个名为 my-great-new-post 的普通文件(不用担心不会与同一存储桶中的文件夹发生名称冲突)

  2. Write a meta-redirect code in that file (I pasted the code below)在那个文件中写一个元重定向代码(我粘贴了下面的代码)

  3. upload file to root bucket (where my-great-new-post folder lays)将文件上传到根存储桶(my-great-new-post 文件夹所在的位置)

  4. modify metadata of the new file and make Content-Type:text/html修改新文件的元数据并制作 Content-Type:text/html

Here lays the content of the file:这是文件的内容:

 <;DOCTYPE html> <html> <head> <meta http-equiv="refresh" content="0. url=/my-great-new-post/index.html"> </head> <body> </body> </html>

If you're using CloudFront, you can use CloudFront functions to create a simple redirection.如果您使用的是 CloudFront,则可以使用CloudFront 函数来创建简单的重定向。

I modified @jkingok's solution.我修改了@jkingok 的解决方案。

  1. Go to CloudFront, and click on Functions.转到 CloudFront,然后单击 Functions。
  2. Click on Create function, enter a name and optional description单击创建函数,输入名称和可选描述
  3. In the development section, enter the code snippet below and publish from the publish tab.在开发部分,输入下面的代码片段并从发布选项卡发布。
    function handler(event) {
      var request = event.request;
      if (request.uri !== "/" && (request.uri.endsWith("/") || request.uri.lastIndexOf(".") < request.uri.lastIndexOf("/"))) {
      if (request.uri.endsWith("/")) {
         request.uri = request.uri.concat("index.html");
      } else {
         request.uri = request.uri.concat("/index.html");
      }
     }
      return request;
   }

Once your function is completed, you can use the function by going to the "Behaviors" tab of your distribution, select the path pattern you want to modify, then under "Function associations", for Viewer Request, select "CloudFront function" as the function type and then select the function you created in the dropdown list.函数完成后,您可以通过转到分配的“行为”选项卡来使用该函数,选择要修改的路径模式,然后在“函数关联”下,对于查看器请求,选择“CloudFront 函数”作为函数类型,然后在下拉列表中选择您创建的函数。

函数关联截图

Once you save the Behaviors, you can test your website.保存行为后,您可以测试您的网站。

NOTE: This solution redirects every URL without extension to "URL/index.html", you can modify the behaviour of the function to what works for you.注意:此解决方案将不带扩展名的每个 URL 重定向到“URL/index.html”,您可以将函数的行为修改为适合您的方式。

When you enable and configure static hosting with S3 you need to access the site via the bucket website endpoint.当您使用 S3 启用和配置静态托管时,您需要通过存储桶网站端点访问该站点。 You can find this URL in the bucket properties in the Static website hosting section.您可以在静态网站托管部分的存储桶属性中找到此 URL。

S3 静态网站托管设置

The URL of the website endpoint will look like this:网站端点的 URL 将如下所示:

http://example-bucket.s3-website-eu-west-1.amazonaws.com/example-folder/

However (confusingly) objects stored in S3 are also accessible via a different URL, this url does not honour the index rules on subfolders.然而(令人困惑的)存储在 S3 中的对象也可以通过不同的 URL 访问,这个 URL 不遵守子文件夹的索引规则。 This URL looks like this:这个 URL 看起来像这样:

https://example-bucket.s3-eu-west-1.amazonaws.com/example-folder/
  1. Configure your Bucket to deliver a static website配置您的 Bucket 以提供静态网站
  2. Create a CloudFront Distribution : set your bucket as the Origin and leave the OriginPath empty (default: / )创建CloudFront 分配:将您的存储桶设置为Origin并将OriginPath留空(默认值: /
  3. Create Route53 RecordSet which links to your CloudFront Distribution创建链接到您的CloudFront 分配Route53 RecordSet

You can find a helpful walkthrough here您可以在此处找到有用的演练

Question: What should happen if your customer enters example.com (without old / new )?问题:如果您的客户输入example.com (没有old / new )会发生什么?

Edit: 2. is optional.编辑: 2.是可选的。 You could also link your Route53 RecordSet to your static website but CloudFront enables you to serve your wesbite with https (with help of AWS Certificate Manager ).您还可以将您的 Route53 RecordSet 链接到您的静态网站,但CloudFront 使您能够使用https (借助AWS Certificate Manager )为您的网站提供服务。

If you are using CDK to create a CloudFrontWebDistribution with an S3 source, then your first guess is probably to do this:如果您使用 CDK 创建带有 S3 源的 CloudFrontWebDistribution,那么您的第一个猜测可能是这样做:

                OriginConfigs = new[] {
                    new SourceConfiguration {
                        S3OriginSource = new S3OriginConfig
                        {
                            S3BucketSource = bucket
                        }
                        Behaviors = new[] { new Behavior { IsDefaultBehavior = true } }
                    }
                }

However, to configure cloudfront to use the website-bucket-url (that does have the behavior to resolve a directory to index.html), you need to use:但是,要将 cloudfront 配置为使用 website-bucket-url(确实具有将目录解析为 index.html 的行为),您需要使用:

                OriginConfigs = new[] {
                    new SourceConfiguration {
                        CustomOriginSource = new CustomOriginConfig
                        {
                            DomainName = bucket.BucketWebsiteDomainName,
                            OriginProtocolPolicy = OriginProtocolPolicy.HTTP_ONLY
                        },
                        Behaviors = new[] { new Behavior { IsDefaultBehavior = true } }
                    }
                }

You need to specify the protocol as HTTP_ONLY because website buckets do not support HTTPS.您需要将协议指定为 HTTP_ONLY,因为网站存储桶不支持 HTTPS。 The default for a CustomOriginSource is HTTPS_ONLY. CustomOriginSource 的默认值为 HTTPS_ONLY。

You can try setting Redirection rules, Here is an untested rule.您可以尝试设置重定向规则,这是一个未经测试的规则。

<RoutingRules>
  <RoutingRule>
    <Condition>
      <KeyPrefixEquals>old</KeyPrefixEquals>
    </Condition>
    <Redirect>
      <ReplaceKeyWith>old/index.html</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>
  <RoutingRule>
    <Condition>
      <KeyPrefixEquals>new</KeyPrefixEquals>
    </Condition>
    <Redirect>
      <ReplaceKeyWith>new/index.html</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM