首页 文章

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

提问于
浏览
51

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

现在,我知道Cloudfront的工作方式不同于S3和亚马逊国家specifically

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

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

更改为编辑模式:Web分布 - 单击“起源”选项卡,单击要编辑的原点,然后单击“编辑” . 您只能为Origin Type为S3 Origin的原点创建原始访问标识 .

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

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

  • 是否可以为从Cloudfront提供的内容设置原始访问标识,其中源是S3网站 endpoints 而不是S3存储桶?

8 回答

  • 1

    IS 这样做的方法 . 而不是通过在下拉列表中选择它(www.example.com.s3.amazonaws.com)将其指向您的桶,将其指向您的桶的静态域(例如www.example.com.s3- website-us -west-2.amazonaws.com):

    enter image description here

    感谢This AWS Forum thread

  • 5

    UPDATE: It looks like I was incorrect! See JBaczuk's answer, which should be the accepted answer on this thread.

    不幸的是,你的两个问题的答案都是否定的 .

    1. Is it possible to specify a default root object for all subdirectories for a statically hosted website on Cloudfront?

    没有 . 如_1434210中所述......

    ...如果定义默认根对象,则对分发子目录的最终用户请求不会返回默认根对象 . 例如,假设index.html是您的默认根对象,CloudFront会在您的CloudFront分配下收到安装目录的最终用户请求:http://d111111abcdef8.cloudfront.net/install/ CloudFront不会返回默认根对象即使index.html的副本出现在安装目录中 . ... CloudFront默认根对象的行为与Amazon S3索引文档的行为不同 . 将Amazon S3存储桶配置为网站并指定索引文档时,即使用户请求存储桶中的子目录,Amazon S3也会返回索引文档 . (索引文档的副本必须出现在每个子目录中 . )

    2. Is it possible to setup an origin access identity for content served from Cloudfront where the origin is an S3 website endpoint and not an S3 bucket?

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

    然而,第二个选项确实开辟了一些有趣的可能性 . 这可能会破坏您尝试执行的操作的目的,但您可以设置自己的服务器,其唯一的工作是成为CloudFront原始服务器 .

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

    或者你可以写一个小的网络应用程序,只需接听这个电话,无论如何直接从S3获取 .

    但我意识到,设置自己的服务器并担心扩展它可能会破坏你首先尝试做的目的 .

  • 4

    激活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 ,然后在 Lambda Function Associations 下选择 Origin Request ,最后将ARN粘贴到新功能中 .

  • 1

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

  • 1

    该问题的解决方法是使用lambda @ edge重写请求 . 只需要为CloudFront分配的查看者请求事件设置lambda,并用默认根文档重写以'/'结尾的所有内容,并且不等于'/',例如index.html的 .

  • 164

    我知道这是一个老问题,但我自己也在努力解决这个问题 . 最终,我的目标不是在目录中设置默认文件,而是更多地获得在文件末尾没有 .html 的情况下提供文件的最终结果

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

  • 1

    有一个"official" guide published on AWS blog建议设置由CloudFront分配触发的Lambda @ Edge功能:

    当然,期望用户始终在每个URL的末尾键入index.html(或者甚至知道它应该在那里)是一种糟糕的用户体验 . 到目前为止,还没有一种简单的方法可以通过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的错误页面 . 设置Custom Error Response将所有403发送到特定文件 . 然后将javascript添加到该文件以将index.html附加到以/结尾的URL . 示例代码:

    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>");
    }
    

相关问题