如何在 AWS Cloudfront (S3) 上获取干净的 URL?

How to get clean URLs on AWS Cloudfront (S3)?

我在 AWS S3 上托管我的静态网站,使用 Cloudfront 作为 CDN,我想知道如何让干净的 URL 正常工作。

我目前必须转到 example.com/about.html 才能获取“关于”页面。我更喜欢 example.com/about 以及我所有其他页面。另外,我有点不得不这样做,因为我的规范 URL 已经设置了元标记和搜索引擎,并且要更改它们会有点多。

Cloudfront 中是否有我没有看到的设置?

更新

我探索了两种选择,马特在下面详细介绍了一种。

首先是在上传到 S3 之前修剪 .html 文件,然后在该文件的 http 中编辑内容 Header。这可能工作得很好,但我不知道如何从命令行编辑内容 headers,我正在写我的 "push website update" bash 脚本。

第二个由下面的 Matt 详细介绍,它利用 S3 的功能识别根默认文件,通常 index.html。可能是一个很好的方法,但它使我的本地测试变得具有挑战性,并且它在 URL 上留下了一个尾部斜杠,这对我不起作用。

当您在 S3(以及扩展名 CloudFront)中托管您的网站时,您可以将 S3 配置为在请求目录时加载 "default" 文件。这叫做 "index document".

例如,您可以将 S3 配置为加载 index.html 作为默认文件。这样,如果请求是 example.com/abc/,那么它将加载 abc/index.html.

当您执行此操作时,如果他们请求 example.com/abc/123.html,那么它将提供 abc/123.html。因此默认文件仅在请求文件夹时适用。

为了解决您对 example.com/about/ 的请求,您可以使用默认文件 index.html 配置您的存储桶,并将 about/index.html 放入您的存储桶。

更多信息可以在亚马逊的文档中找到:Index Document Support

当您的 S3 存储桶配置为网站端点时,您可以通过使用自定义源来克服 丑陋的 url,并使用 Cloudfront 分配。缺点是您无法将 Cloudfront 配置为使用 HTTPS 在 Cloudfront 和您的来源之间进行通信。您仍然可以使用 HTTPS,只是不是端到端加密。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https-cloudfront-to-s3-origin.html

您可以使用 Lambda 作为您网站的反向代理。

在 API 网关中,您需要创建 "proxy resource" 资源路径 =“{proxy+}”

然后,创建一个 Lambda 函数来路由请求:

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const myBucket = 'myBucket';

exports.handler = async (event) => {

    var responseBody = "";

    if (event.path=="/") {
        responseBody = "<h1>My Landing Page</h1>";
        responseBody += "<a href='/about'>link to about page</a>";
        return buildResponse(200, responseBody);
    }

    if (event.path == "/about") {

        var params = { 
            Bucket: myBucket,
            Key: 'path/to/about.html',
        };

        const data = await s3.getObject(params).promise();

        return buildResponse(200, data.Body.toString('utf-8'));
    }

    return buildResponse(404, 'Page Not Found');

};


function buildResponse(statusCode, responseBody) {

    var response = {
        "isBase64Encoded": false,
        "statusCode": statusCode,
        "headers": {
            "Content-Type" : "text/html; charset=utf-8"
        },
        "body": responseBody,
    };

    return response;
}

然后您可以使用您的自定义域为您的 API 网关创建 CloudFront 分配。

有关详细信息,请查看此答案:

试试 AWS Lamda@Edge。它彻底解决了这个问题。

首先,创建一个 AWS Lambda 函数,然后将您的 CloudFront 作为触发器附加。

在此 AWS Lamda 页面的代码部分,将代码段添加到下面的存储库中。

https://github.com/CloudUnder/lambda-edge-nice-urls/blob/master/lambdaRewrite.js

注意 repo 的自述部分中的选项