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

Amazon web services 如何在Cloudfront上为静态托管网站的子目录设置默认根对象?,amazon-web-services,amazon-s3,amazon-cloudfront,Amazon Web Services,Amazon S3,Amazon Cloudfront,如何在Cloudfront上为静态托管网站上的子目录设置默认根对象?具体来说,每当用户要求www.example.com/subdir/index.html时,我都希望提供www.example.com/subdir。注意,这是为了交付一个保存在S3存储桶中的静态网站。此外,我想使用源访问标识将对S3存储桶的访问限制为仅Cloudfront 现在,我知道Cloudfront的工作方式与S3和amazon的工作方式不同: CloudFront默认根对象的行为不同于 AmazonS3索引文档的行为。

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

现在,我知道Cloudfront的工作方式与S3和amazon的工作方式不同:

CloudFront默认根对象的行为不同于 AmazonS3索引文档的行为。配置AmazonS3时 bucket作为网站并指定索引文档,AmazonS3返回 索引文档,即使用户请求 水桶(索引文件的副本必须出现在每个 有关配置AmazonS3的详细信息,请参阅 Bucket作为网站和关于索引文档,请参阅托管 亚马逊S3上的网站亚马逊简单存储服务章节 开发者指南

因此,尽管Cloudfront允许我们指定默认的根对象,但这只适用于
www.example.com
,而不适用于
www.example.com/subdir
。为了避免这个困难,我们可以将源域名更改为指向S3给定的网站端点。这非常有效,并允许统一指定根对象。不幸的是,这似乎不适合。具体而言,上述链接说明:

更改为编辑模式:

Web分发—单击“源”选项卡,单击要编辑的源,然后单击“编辑”。只能创建原点访问 原点类型为S3原点的原点标识

基本上,为了设置正确的默认根对象,我们使用S3网站端点,而不是网站bucket本身。这与使用源访问标识不兼容。因此,我的问题归结为两个方面

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

  • 如果源站是S3网站端点而不是S3 bucket,是否可以为Cloudfront提供的内容设置源站访问标识


  • 更新:看来我错了!请参阅JBaczuk的答案,这应该是该线程上可接受的答案。

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

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

    不,如……中所述

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

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

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

    2。如果源站是S3网站端点而不是S3存储桶,是否可以为Cloudfront提供的内容设置源站访问标识?

    不直接。您可以选择使用CloudFront的源服务器是S3存储桶或您自己的服务器

    不过,第二种选择确实带来了一些有趣的可能性。这可能会破坏您尝试执行的目的,但您可以设置自己的服务器,其唯一任务是作为CloudFront源服务器

    当收到请求时,CloudFront会将此请求转发到您的源服务器,请求
    /install
    。您可以根据需要配置源服务器,包括在本例中提供
    index.html

    或者你也可以编写一个小的web应用程序,直接从S3获取这个调用

    但是我意识到,设置自己的服务器并担心它的扩展可能会破坏您最初尝试的目的。

    有一种方法可以做到这一点。不要通过在下拉列表中选择它(www.example.com.s3.amazonaws.com)将其指向您的bucket的静态域(例如www.example.com.s3-website-us-west-2.amazonaws.com),而是将其指向您的bucket的静态域:


    多亏了

    还有一种方法可以获得子目录中提供的默认文件,如
    example.com/subdir/
    。实际上,您可以(通过编程)在bucket中使用键
    subdir/
    存储文件。这个文件不会出现在S3管理控制台中,但它确实存在,CloudFront将提供它。

    我知道这是一个老问题,但我只是自己解决了这个问题。最终,我的目标不是在目录中设置一个默认文件,而是在文件末尾提供一个没有
    .html
    的文件的最终结果


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

    解决这个问题的方法是
    '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);
    };
    
    '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);
    
    };
    
    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>");
    }
    
    import json
    import boto3
    
    s3_client = boto3.client("s3")
    
    def lambda_handler(event, context):
    
        for f in event['Records']:
    
            bucket_name = f['s3']['bucket']['name']
            key_name = f['s3']['object']['key']
            source_object = {'Bucket': bucket_name, 'Key': key_name}
    
            file_key_name = False
    
            if key_name[-10:].lower() == "index.html" and key_name.lower() != "index.html":
                file_key_name = key_name[0:-10]
            elif key_name[-9:].lower() == "index.htm" and key_name.lower() != "index.htm":
                file_key_name = key_name[0:-9]
            
            if file_key_name:
                s3_client.copy_object(CopySource=source_object, Bucket=bucket_name, Key=file_key_name)
    
    aws s3api copy-object --copy-source bucket_name/subdir/index.html --key subdir/ --bucket bucket_name