wye*_*r33 77 amazon-s3 amazon-web-services amazon-cloudfront
如何在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 Type为S3 Origin的原点创建原始访问标识.
基本上,为了设置正确的默认根对象,我们使用S3网站端点而不是网站存储桶本身.这与使用原始访问标识不兼容.因此,我的问题归结为两者
是否可以为Cloudfront上的静态托管网站的所有子目录指定默认根对象?
是否可以为从Cloudfront提供的内容设置原始访问标识,其中源是S3网站端点而不是S3存储桶?
JBa*_*zuk 201
有IS办法做到这一点.而不是通过在下拉列表中选择它(www.example.com.s3.amazonaws.com)将其指向您的桶,将其指向您的桶的静态域(例如www.example.com.s3- website-us -west-2.amazonaws.com):
感谢此AWS论坛主题
ktu*_*nik 48
下面创建一个简单的 JavaScript 函数
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
Run Code Online (Sandbox Code Playgroud)
在这里阅读更多信息
Aid*_*din 18
我完全同意这是一个荒谬的问题!事实上,CloudFront 知道index.html
充当默认根对象,但他们仍然说它不适用于子目录(源),这是完全奇怪的!
CloudFront 默认根对象的行为与 Amazon S3 索引文档的行为不同。当您将 Amazon S3 存储桶配置为网站并指定索引文档时,即使用户请求存储桶中的子目录,Amazon S3 也会返回索引文档。
我个人认为,AWS 已经做到了这一点,因此 CloudFront 仅成为 CDN(加载资产,其中没有任何逻辑),并且对网站中路径的每个请求都应由“服务器”(例如 EC2 节点)提供服务/Php 服务器,或 Lambda 函数。)
这种限制的存在是否是为了增强安全性,或者将事物分开(即逻辑和存储分开),或者赚更多的钱(强制人们拥有专用服务器,即使是静态内容)还有待争论。
无论如何,我在这里总结了可能的解决方案及其优缺点。
这是最简单的一个,最初由 @JBaczuk答案以及此 github gist发布。由于 S3 已经支持index.html
通过静态网站托管在子目录中提供服务,因此您需要做的就是:
http://<bucket-name>.s3-website-us-west-2.amazonaws.com
/about/
、/about
、 和/about/index.html
并将最后两个正确重定向到第一个。如果您在 S3 存储桶中的文件不在 S3 的根目录中(例如,/artifacts/*
然后转到www.domain.com/about
(不带尾随/
)会将您重定向到www.domain.com/artifacts/about
您根本不想要的内容!基本上,如果您提供服务,S3 中的重定向/about
会中断/about/
来自 CloudFront 的路径和文件路径(从根目录)不匹配。
安全性和功能性:您无法将 S3 设为私有。显然,这是因为 CloudFront 的Origin Access Identity将不受支持,因为 CloudFront 被指示将此 Origin 作为随机网站。这意味着用户可以直接从 S3 获取文件,由于安全/WAF 问题,这可能不是您所期望的,并且如果您的 JS/html 仅依赖于您的域的路径,则网站实际上可以正常工作。
[也许是一个问题] CloudFront 和 S3 之间的通信不是建议优化内容的方式。
[也许?]有人抱怨说它对于发行版中的多个起源(即想要/blog
去某个地方)不能顺利工作
[也许?]有人抱怨它没有按预期保留原始查询参数。
这是官方解决方案(尽管该文档是 2017 年的)。还有一个准备启动的第 3 方应用程序(github 中的 JavaScript 源代码)和示例 Python Lambda 函数(此答案)。
从技术上讲,通过这样做,您可以创建一个迷你服务器(他们称之为无服务器!),仅向 CloudFront 的 S3 源请求提供服务(因此,它基本上位于 CloudFront 和 S3 之间。)
/about/
两者/about
(从后者重定向而不跟踪/
到前者)。/about?foo=bar
301 重定向到/about/
NOT也是如此/about/?foo=bar
。您需要对该 lambda 函数进行更改才能使其正常工作。/about/
为规范版本。如果您想/about
成为规范版本(即其他格式通过 301 重定向到它),您必须对脚本进行更改。它是前两者之间的解决方案——它支持 OAI(私有 S3)并且不需要服务器。虽然有点恶心!
您在这里要做的是,运行一个脚本,为/about/index.html
它的每个子目录在 S3 中创建一个名为 (has key
of)的对象/about
,并将该 HTML 文件(内容和content-type
)复制到该对象中。
示例脚本可以在此 Reddit 答案和使用 AWS CLI 的答案中找到。
/about
但不/about/
支持尾随/
。虽然它看起来不像真实的东西,但这个答案值得一些赞扬,IMO!
您让拒绝访问(404 变成 403)通过,然后捕获它们,并通过 JS 手动将它们重定向到正确的位置。
history.replace
。ken*_*ske 11
激活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);
};
Run Code Online (Sandbox Code Playgroud)
发布功能后,请转至AWS控制台中的cloudfront分发.转到Behaviors
,然后选择Origin Request
下Lambda Function Associations
,最后将ARN粘贴到新功能.
还有另一种方法可以在子目录中提供默认文件,例如example.com/subdir/
.实际上,您可以(以编程方式)存储带有密钥的文件subdir/
.此文件不会显示在S3管理控制台中,但它实际存在,CloudFront将为其提供服务.
AWS 博客上发布了一份“官方”指南,建议设置由您的 CloudFront 分配触发的 Lambda@Edge 函数:
当然,期望用户总是在每个 URL 的末尾键入 index.html(甚至知道它应该在那里)是一种糟糕的用户体验。到目前为止,还没有一种简单的方法可以通过 CloudFront 向用户提供这些更简单的 URL(相当于 Apache Web 服务器配置中的 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);
};
Run Code Online (Sandbox Code Playgroud)
按照上面链接的指南查看设置此所需的所有步骤,包括 S3 存储桶、CloudFront 分配和Lambda@Edge函数创建。
如果您不想使用 labmda、javascript 或其他 s3 配置...正如 johan-gorter 和 jeremie 所指出的,index.html
可以将其存储为带有 key 的对象subdir/
。aws
我验证了这种方法的有效性,并且似乎是使用CLI实现此目的的最简单方法s3api copy-object
aws s3api copy-object --copy-source bucket_name/subdir/index.html --key subdir/ --bucket bucket_name
Run Code Online (Sandbox Code Playgroud)
更新:看来我错了!请参阅 JBaczuk 的答案,这应该是该线程上接受的答案。
不幸的是,你的两个问题的答案是否定的。
1. 是否可以为 Cloudfront 上静态托管网站的所有子目录指定默认根对象?
否。如AWS CloudFront 文档中所述...
...如果您定义默认根对象,则最终用户对发行版子目录的请求不会返回默认根对象。例如,假设
index.html
是您的默认根对象,并且 CloudFront 收到最终用户对 CloudFront 分配下的安装目录的请求:http://d111111abcdef8.cloudfront.net/install/
即使有副本,CloudFront 也不会返回默认根对象
index.html
即使安装目录中出现 的...
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 获取它。
但我意识到,建立自己的服务器并担心扩展它可能会违背您最初尝试做的事情的目的。
归档时间: |
|
查看次数: |
18836 次 |
最近记录: |