How do you set a default root object for subdirectories for a statically hosted website on Cloudfront?

前端 未结 9 1933
[愿得一人]
[愿得一人] 2020-12-22 17:33

How do you set a default root object for subdirectories on a statically hosted website on Cloudfront? Specifically, I\'d like www.example.com/subdir/index.html

相关标签:
9条回答
  • 2020-12-22 18:33

    Workaround for the issue is to utilize lambda@edge for rewriting the requests. One just needs to setup the lambda for the CloudFront distribution's viewer request event and to rewrite everything that ends with '/' AND is not equal to '/' with default root document e.g. index.html.

    0 讨论(0)
  • 2020-12-22 18:34

    There is an "official" guide published on AWS blog that recommends setting up a Lambda@Edge function triggered by your CloudFront distribution:

    Of course, it is a bad user experience to expect users to always type index.html at the end of every URL (or even know that it should be there). Until now, there has not been an easy way to provide these simpler URLs (equivalent to the DirectoryIndex Directive in an Apache Web Server configuration) to users through CloudFront. Not if you still want to be able to restrict access to the S3 origin using an OAI. However, with the release of Lambda@Edge, you can use a JavaScript function running on the CloudFront edge nodes to look for these patterns and request the appropriate object key from the S3 origin.

    Solution

    In this example, you use the compute power at the CloudFront edge to inspect the request as it’s coming in from the client. Then re-write the request so that CloudFront requests a default index object (index.html in this case) for any request URI that ends in ‘/’.

    When a request is made against a web server, the client specifies the object to obtain in the request. You can use this URI and apply a regular expression to it so that these URIs get resolved to a default index object before CloudFront requests the object from the origin. Use the following code:

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

    Follow the guide linked above to see all steps required to set this up, including S3 bucket, CloudFront distribution and Lambda@Edge function creation.

    0 讨论(0)
  • 2020-12-22 18:36

    Activating S3 hosting means you have to open the bucket to the world. In my case, I needed to keep the bucket private and use the origin access identity functionality to restrict access to Cloudfront only. Like @Juissi suggested, a Lambda function can fix the redirects:

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

    After you publish your function, go to your cloudfront distribution in the AWS console. Go to Behaviors, then chooseOrigin Request under Lambda Function Associations, and finally paste the ARN to your new function.

    0 讨论(0)
提交回复
热议问题