如何为Cloudfront上的静态托管网站的子目录设置默认根对象?


96

如何在Cloudfront上的静态托管网站上为子目录设置默认根对象?具体来说,我希望www.example.com/subdir/index.html在用户要求时提供服务www.example.com/subdir。请注意,这是为了交付S3存储桶中的静态网站。此外,我想使用原始访问身份将对S3存储桶的访问限制为仅Cloudfront。

现在,我知道Cloudfront的工作方式与S3和Amazon状态特别不同

CloudFront默认根对象的行为与Amazon S3索引文档的行为不同。当您将Amazon S3存储桶配置为网站并指定索引文档时,即使用户请求存储桶中的子目录,Amazon S3也会返回索引文档。(索引文档的副本必须出现在每个子目录中。)有关将Amazon S3存储桶配置为网站以及有关索引文档的更多信息,请参阅Amazon Simple Storage Service开发人员指南中的在Amazon S3上托管网站。

因此,即使Cloudfront允许我们指定默认的根对象,这仅适用于www.example.com而不适用于www.example.com/subdir。为了解决这个难题,我们可以更改原始域名以指向S3给定的网站端点。这很好用,并且可以统一指定根对象。不幸的是,这似乎与原始访问身份不兼容。具体来说,以上链接指出:

更改为编辑模式:

Web分发–单击“起源”选项卡,单击要编辑的起源,然后单击“编辑”。您只能为Origin类型为S3 Origin的Origin创建一个Origin访问标识。

基本上,为了设置正确的默认根对象,我们使用S3网站终结点而不是网站存储桶本身。这与使用原始访问身份不兼容。因此,我的问题归结为

  1. 是否可以为Cloudfront上的静态托管网站的所有子目录指定默认的根对象?

  2. 是否可以为从Cloudfront提供的内容(其来源是S3网站终结点而不是S3存储桶)设置来源访问身份?


1
我认为现在可以使用Lambda @ edge做到这一点,使用一个将所有以/结尾的URL重定向到/index.html的函数,我将在我的网站上进行尝试并报告结果并发布详细的配置作为答案。
Cristian Măgherușan-Stanciu

Answers:


1

更新:看来我不正确!请参阅JBaczuk的答案,它应该是该线程上可接受的答案。

不幸的是,这两个问题的答案都为否。

1.是否可以为Cloudfront上的静态托管网站的所有子目录指定默认的根对象?

否。如AWS CloudFront文档中所述 ……

...如果定义了默认的根对象,则最终用户对分发的子目录的请求不会返回默认的根对象。例如,假设index.html您是默认的根对象,并且CloudFront收到最终用户对CloudFront发行版下的安装目录的请求:

http://d111111abcdef8.cloudfront.net/install/

即使index.html在安装目录中出现的副本,CloudFront也不会返回默认的根对象。

...

CloudFront默认根对象的行为与Amazon S3索引文档的行为不同。当您将Amazon S3存储桶配置为网站并指定索引文档时,即使用户请求存储桶中的子目录,Amazon S3也会返回索引文档。(索引文档的副本必须出现在每个子目录中。)

2.是否可以为从Cloudfront提供的内容设置来源访问身份,其中来源是S3网站终结点而不是S3存储桶?

不直接。CloudFront的起源选项是S3存储桶或您自己的服务器。

不过,第二个选项确实带来了一些有趣的可能性。这可能无法达到您要执行的操作的目的,但是您可以设置自己的服务器,其唯一的工作就是成为CloudFront源服务器。

收到http://d111111abcdef8.cloudfront.net/install/的请求时,CloudFront会将此请求转发到您的原始服务器,并询问/install。您可以根据需要配置原始服务器,包括提供服务index.html在这种情况下。

或者,您也可以编写一个小的Web应用程序,该应用程序仅接受此调用并直接从S3获取它。

但是我意识到,设置自己的服务器并担心对其进行扩展可能会一开始就无法实现您想要做的目的。


我对此有一个问题,那就是要使它正常工作就意味着您将拥有两(2)个能够访问s3网站的URL。您的云端前端网址和s3网址(bucket_name.s3-website-us-east-1.amazonaws.com)
海登

218

IS办法做到这一点。与其通过在下拉列表(www.example.com.s3.amazonaws.com)中选择它来将其指向您的存储桶,而是将其指向存储桶的静态域(例如www.example.com.s3-website-us -west-2.amazonaws.com):

在此处输入图片说明

感谢这个AWS论坛主题


6
有人知道在使用s3来源与网络来源时这是否收费不同?
fideloper '16

3
如果我只想提供整个网站和文件,这样是否可以正常工作HTTPS
Manjit Kumar

3
这是否意味着必须将S3启用为Web服务器?
安东尼·孔

6
OP明确表示这种方法对他不起作用:“为了解决这一难题,我们可以更改原始域名,使其指向S3给出的网站端点。这很好用,并且可以统一指定根对象。不幸的是, ,这似乎与原始访问身份不兼容”。AWS自己似乎被推荐LAMDA @缘此- aws.amazon.com/blogs/compute/...
icyitscold

3
这是不兼容的Cloud Front-Origin Access Identity。您将无法通过这种方式限制对S3存储桶的访问。
rocketspacer19年

15

激活S3托管意味着您必须向世界敞开大门。就我而言,我需要保持存储桶为私有,并使用源访问身份功能来仅限制对Cloudfront的访问。就像@Juissi建议的那样,Lambda函数可以修复重定向:

'use strict';

/**
 * Redirects URLs to default document. Examples:
 *
 * /blog            -> /blog/index.html
 * /blog/july/      -> /blog/july/index.html
 * /blog/header.png -> /blog/header.png
 *
 */

let defaultDocument = 'index.html';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if(request.uri != "/") {
        let paths = request.uri.split('/');
        let lastPath = paths[paths.length - 1];
        let isFile = lastPath.split('.').length > 1;

        if(!isFile) {
            if(lastPath != "") {
                request.uri += "/";
            }

            request.uri += defaultDocument;
        }

        console.log(request.uri);
    }

    callback(null, request);
};

发布功能后,请转到AWS控制台中的Cloudfront发行版。转到Behaviors,然后Origin Request在下选择Lambda Function Associations,最后将ARN粘贴到新功能中。


5
有一个准备部署类似于一个lambda表达式:serverlessrepo.aws.amazon.com/applications/...
marcanuy

这里的问题是此功能需要部署到us-east-1,因此,如果您的公司受到严格的GDPR监管,并且不允许在德国以外的任何地方进行业务,那么这将不适合您。
Renato Gama

5

还有另一种方法可以在子目录(例如)中提供默认文件example.com/subdir/。您实际上可以(以编程方式)将带有密钥的文件存储subdir/在存储桶中。该文件不会显示在S3管理控制台中,但实际上存在,并且CloudFront将为其提供文件。


S3将subdir /转换为subdir;当您尝试上传HTML时。另外,当您尝试访问example.com/subdir/时,它也会失败,并且如果您尝试访问example.com/subdir,也会失败。它下载HTML文件而不是呈现它。
jacobfogg


4

在AWS博客发布了一个“官方”指南,建议设置由您的CloudFront发行版触发的Lambda @ Edge函数:

当然,期望用户总是在每个URL的末尾键入index.html(或者甚至知道它应该在该URL中)是一种糟糕的用户体验。到目前为止,还没有一种简便的方法可以通过CloudFront向用户提供这些更简单的URL(相当于Apache Web Server配置中的DirectoryIndex指令)。如果您仍然希望能够使用OAI限制对S3原点的访问,则不会。但是,随着Lambda @ Edge的发布,您可以使用在CloudFront边缘节点上运行的JavaScript函数来查找这些模式,并从S3来源请求适当的对象密钥。

在此示例中,您可以使用CloudFront边缘的计算能力来检查来自客户端的请求。然后重新编写请求,以便CloudFront为以'/'结尾的任何请求URI请求默认索引对象(在这种情况下为index.html)。

当针对Web服务器发出请求时,客户端会在请求中指定要获取的对象。您可以使用此URI并对其应用正则表达式,以便在CloudFront从源请求该对象之前将这些URI解析为默认索引对象。使用以下代码:

'use strict';
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;

    // 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(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);

};

请按照上面链接的指南查看设置步骤,包括S3存储桶,CloudFront发行版和Lambda @ Edge函数创建。


2

使用lambda @ edge的另一种替代方法是使用CloudFront的错误页面。设置“ 自定义错误响应”以将所有403发送到特定文件。然后将javascript添加到该文件,以将index.html附加到以/结尾的网址。样例代码:

if ((window.location.href.endsWith("/") && !window.location.href.endsWith(".com/"))) {
    window.location.href = window.location.href + "index.html";
}
else {
    document.write("<Your 403 error message here>");
}

1

我知道这是一个古老的问题,但是我自己却为此苦苦挣扎。最终,我的目标是减少在目录中设置默认文件的工作,而更多的是获得没有.html在文件末尾提供的文件的最终结果

我最终.html从文件名中删除,并以编程方式/手动将mime类型设置为text/html。它不是传统方法,但确实有效,并且在不牺牲cloudformation好处的情况下满足了我对漂亮url的要求。设置mime类型很烦人,但我认为付出的代价很小

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.