Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Amazon s3 未找到时指向回退S3域子文件夹的Lambda脚本_Amazon S3 - Fatal编程技术网

Amazon s3 未找到时指向回退S3域子文件夹的Lambda脚本

Amazon s3 未找到时指向回退S3域子文件夹的Lambda脚本,amazon-s3,Amazon S3,根据这一点,以及下面的一段代码,允许我将S3 bucket中的一个子文件夹指向我的域 但是,在未找到子域的情况下,我会收到以下错误消息: <Error> <Code>AccessDenied</Code> <Message>Access Denied</Message> <RequestId>2CE9B7837081C817</RequestId> <HostId> T3p7mzSYztPhXetUu

根据这一点,以及下面的一段代码,允许我将S3 bucket中的一个子文件夹指向我的域

但是,在未找到子域的情况下,我会收到以下错误消息:

<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>2CE9B7837081C817</RequestId>
<HostId>
T3p7mzSYztPhXetUu7GHPiCFN6l6mllZgry+qJWYs+GFOKMjScMmRNUpBQdeqtDcPMN3qSYU/Fk=
</HostId>
</Error>
我不希望它显示此错误消息,相反,在这种情况下,我希望从另一个S3 bucket子域(即
example bucket.S3 website.us-east-2.amazonaws.com/error
)提供服务,例如,在那里,用户将收到一条奇特的错误消息。因此,在没有找到S3 bucket子文件夹的情况下,它应该返回到那里。如何通过更改下面的节点函数来实现这一点

'use strict';

// if the end of incoming Host header matches this string, 
// strip this part and prepend the remaining characters onto the request path,
// along with a new leading slash (otherwise, the request will be handled
// with an unmodified path, at the root of the bucket)

const remove_suffix = '.example.com';

// provide the correct origin hostname here so that we send the correct 
// Host header to the S3 website endpoint

const origin_hostname = 'example-bucket.s3-website.us-east-2.amazonaws.com'; // see comments, below

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const host_header = headers.host[0].value;

    if(host_header.endsWith(remove_suffix))
    {
        // prepend '/' + the subdomain onto the existing request path ("uri")
        request.uri = '/' + host_header.substring(0,host_header.length - remove_suffix.length) + request.uri;
    }

    // fix the host header so that S3 understands the request
    headers.host[0].value = origin_hostname;

    // return control to CloudFront with the modified request
    return callback(null,request);
};

Lambda@Edge函数是一个源请求触发器——它在检查CloudFront缓存并发生缓存未命中后运行,紧接着在请求(被触发器代码修改后的状态)发送到源服务器之前运行。当响应从源站到达时,此代码已完成,无法用于修改响应

有几种解决方案,包括一些概念上有效但效率极低的解决方案。尽管如此,为了彻底起见,我还是要提到这些以及更清洁/更好的解决方案

Lambda@Edge有:

  • 查看器请求-当请求第一次到达CloudFront时,在检查缓存之前;为每一个请求开火
  • 原始请求-在确认请求为缓存未命中之后,但在将请求发送到原始服务器之前;仅在缓存中触发未命中
  • 源响应-在从源服务器返回响应(无论是成功还是错误)之后,但在响应可能存储在缓存中并返回给查看器之前;如果此触发器修改响应,修改后的响应将存储在CloudFront缓存(如果可缓存)中,并返回给查看器;仅在缓存未命中时激发
  • 查看器响应-在响应返回到查看器之前,无论是从源站还是缓存;为每个非错误响应激发,除非该响应是由查看器请求触发器自发发出的,或者是将状态代码设置为200(明确的反模式,但仍然可能)的自定义错误文档的结果,或者是CloudFront生成的HTTP到HTTPS重定向
任何触发点都可以控制信号流,从而改变CloudFront通常会做的事情——例如,如果您直接从源站请求触发器生成响应,CloudFront实际上不会联系源站。。。因此,从理论上讲,您可以检查原始请求触发器中的S3,看看请求是否会成功,并生成自定义错误响应。AWS Javascript SDK自动绑定到Lambda@Edge环境。从技术上讲,这几乎在任何情况下都可能是一个糟糕的想法,因为它会因为对S3的额外“前瞻”请求而增加成本和延迟

另一个选项是编写一个单独的原始响应触发器来检查错误,如果发生错误,则用来自触发器代码的自定义响应替换它。但这种想法也不可行,因为该触发器将触发对缓存未命中的所有响应,无论是成功还是失败,增加成本和延迟,在大多数情况下浪费时间

一个更好的想法(成本、性能、易用性)是,它允许您定义一个特定的HTML文档,CloudFront将使用该文档处理与指定代码匹配的每个错误(例如403表示拒绝访问,如原始问题所示)。在处理这些错误时,CloudFront还可以将403更改为404。这需要在错误文件的源是bucket时执行以下几项操作:

  • 创建指向桶的第二个CloudFront原点
  • 创建一个新的缓存行为,将一条路径(例如,
    /shared/errors/not found.html
    )精确地路由到错误文件,再路由到新的源(这意味着您不能在任何子域上使用该路径——它总是在任何时候被请求时直接转到错误文件)
  • 为代码403配置CloudFront自定义错误响应,以使用路径
    /shared/errors/not found.html
  • 至少在测试时,将错误缓存最小TTL设置为0,以避免自己遇到一些挫折。请参阅但忽略我说过的“将
    自定义错误响应设置为
    ”部分
但是。。。这可能需要也可能不需要,因为S3的web托管功能还包括可选支持。您需要在原始bucket中创建一个HTML文件,在bucket上启用网站托管功能,并将CloudFront源域名更改为bucket的网站托管端点,该端点位于S3控制台中,但形式为
${bucket}.s3website.${region}.amazonaws.com
。在某些地区,由于传统原因,主机名可能在
s3网站
之后有一个破折号
-
而不是一个点
,但点格式应该适用于任何地区


我几乎不愿意提及脑海中出现的另一个选项,因为它相当先进,我担心描述可能会显得相当复杂。。。但是你也可以做下面的事情,这将是非常巧妙的,因为它将允许你为每个错误的URL请求生成一个定制的HTML页面

创建一个CloudFront,主bucket作为主bucket,第二个空的“占位符”bucket作为辅助bucket。第二个bucket的唯一用途是为CloudFront提供一个它计划连接到的有效名称,尽管我们实际上不会连接到它,下面可能会很清楚

当请求未能发送到主原点(与配置的错误状态代码之一匹配)时,将联系辅助原点。这是为了处理这个案件
event.Records[0].cf.request.origin.s3.domainName     # S3 rest endpoints
event.Records[0].cf.request.origin.custom.domainName # non-S3 origins and S3 website-hosting endpoints