服务索引文件而不是下载提示 [英] Serve index file instead of download prompt

查看:68
本文介绍了服务索引文件而不是下载提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的网站托管在S3上,并且CloudFront作为CDN,并且我需要这两个URL表现相同并在目录中提供index.html文件:

I have my website hosted on S3 with CloudFront as a CDN, and I need these two URLs to behave the same and to serve the index.html file within the directory:

example.com/directory
example.com/directory /

最后带有 / 的那个错误地提示浏览器下载零字节文件,并使用随机哈希作为文件名。没有斜线,它将返回我的404页面。

The one with the / at the end incorrectly prompts the browser to download a zero byte file with a random hash for the name of the file. Without the slash it returns my 404 page.

如何获取两条路径在目录中传递index.html文件?

How can I get both paths to deliver the index.html file within the directory?

如果我有办法做到,那就太好了!这就是我的期望,但是如果没有,我可能会尝试使用Lambda @ Edge进行重定向。无论如何,我还是需要其他方法,因此有关如何从Lambda @ Edge进行301或302重定向的一些说明也将有所帮助:)

If there's a way I'm "supposed" to do this, great! That's what I'm hoping for, but if not I'll probably try to use Lambda@Edge to do a redirect. I need that for some other situations anyway, so some instructions on how to do a 301 or 302 redirect from Lambda@Edge would be helpful too : )

更新(根据约翰·汉利的评论)

curl -i https://www.example.com/directory/

HTTP/2 200 
content-type: application/x-directory
content-length: 0
date: Sat, 12 Jan 2019 22:07:47 GMT
last-modified: Wed, 31 Jan 2018 00:44:16 GMT
etag: "[id]"
accept-ranges: bytes
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 [id].cloudfront.net (CloudFront)
x-amz-cf-id: [id]

更新

CloudFront设置了一个行为,将http转发到https并将请求发送到S3。在错误选项卡下,它还具有404错误路由。

CloudFront has one behavior set, forwarding http to https and sending the requests to S3. It also has a 404 error route under the errors tab.

推荐答案

S3仅在启用后会自动提供索引文件。使用存储桶的网站托管功能,通过指向存储桶的网站托管端点, $ {bucket} .s3-website。$ {region} .amazonaws.com 比存储桶的通用REST端点 $ {bucket} .s3.amazonaws.com

S3 only offers automatic index documents when you've enabled and are using the web site hosting features of the bucket, by pointing to the bucket's website hosting endpoint, ${bucket}.s3-website.${region}.amazonaws.com rather than the generic REST endpoint of the bucket, ${bucket}.s3.amazonaws.com.

网站端点和REST端点具有众多差异,包括这一点。

Web site endpoints and REST endpoints have numerous differences, including this one.

之所以看到对象键的这些0字节文件以 / 结尾,是因为您正在创建使用S3控制台或其他实际创建0字节对象的实用程序将存储桶中的文件夹对象包含在存储桶中。一旦文件夹中包含对象,就不需要它们了-但是它们是在S3控制台中显示空文件夹的唯一方法,该控制台显示名为 foo / 作为名为 foo 的文件夹,即使没有其他键前缀为 foo / 的对象。即使在S3中的对象从不真正位于文件夹中,它也是控制台中文件夹层次结构可视化仿真的一部分。

The reason you're seeing these 0-byte files for object keys ending in / is because you are creating folder objects in the bucket using the S3 console or another utility that actually creates the 0-byte objects. They aren't needed, once the folders have objects "in" them -- but they're the only way to display an empty folder in the S3 console, which displays an object named foo/ as a folder named foo, even if there are no other objects with a key prefix of foo/. It's part of the visual emulation of a folder hierarchy in the console, even though objects in S3 are never really "in" folders.

如果出于某些原因您需要使用REST端点(例如,您不想公开存储桶),那么您需要在CloudFront中使用两个Lambda @ Edge触发器来相当接近地模拟此功能。

If for some reason you need to use the REST endpoint -- such as you don't want to make the bucket public -- then you need two Lambda@Edge triggers in CloudFront, to emulate this functionality fairly closely.

原始请求触发器可以在检查CloudFront缓存之后,将请求发送到源之前检查和修改请求。我们用它来检查以 / 结尾的路径,并在找到后附加 index.html

An Origin Request trigger can inspect and modify requests after the CloudFront cache is checked, before the request is sent to the origin. We use this to check for a path ending in / and append index.html if we find that.

原始响应触发器可以在将响应写入到CloudFront缓存之前检查并可能修改响应。原始响应触发器还可以检查在生成响应的请求之前的原始请求。我们使用它来检查响应是否为错误。如果是这样,并且原始请求似乎不是不是,则是针对索引文档或文件(具体来说,路径中的最后斜杠后,文件至少应包含一个字符,然后是一个点,再加上至少一个字符-如果是,则可能是文件)。如果这些都不是,我们将重定向到原始路径,再加上最终的 /

An Origin Response trigger can inspect and potentially modify responses, before they are written into the CloudFront cache. The Origin Response trigger can also inspect the original request that preceded the request that generated the response. We use this to check whether the response is an error. If it is, and the original request does not appear to be for an index document or a file (specifically, after the final slash in the path, a "file" has at least one character, followed by a dot, followed by at least one more character -- and if so, that's probably a "file"). If it's neither one of those things, we redirect to the original path plus a final / that we append.

原始请求和原始响应仅在缓存未命中时触发触发。发生缓存命中时,不会触发任何触发器,因为它们位于CloudFront的原始端(缓存的背面)。可以从缓存处理的请求是从缓存处理的,因此不会调用触发器。

Origin Request and Origin Response triggers fire only on cache misses. When there is a cache hit, neither trigger fires, because they are on the origin side of CloudFront -- the back side of the cache. Requests that can be served from the cache are served from the cache, so the triggers are not invoked.

以下是用Node.js 8.10编写的Lambda @ Edge函数。 。这个Lambda函数修改其行为,以便根据上下文将其作为源请求或源响应。在Lambda中发布版本后,将该版本的ARN与CloudFront缓存行为设置关联为两者原始请求和原始响应触发器。

The following is a Lambda@Edge function written in Node.js 8.10. This one Lambda function modifies its behavior so that it it behaves as either origin request or origin response, depending on context. After publishing a version in Lambda, associate that version's ARN with the CloudFront Cache Behavior settings as both an Origin Request and an Origin Response trigger.

'use strict';

// combination origin-request, origin-response trigger to emulate the S3
// website hosting index document functionality, while using the REST
// endpoint for the bucket

// https://stackoverflow.com/a/54263794/1695906

const INDEX_DOCUMENT = 'index.html'; // do not prepend a slash to this value

const HTTP_REDIRECT_CODE = '302'; // or use 301 or another code if desired
const HTTP_REDIRECT_MESSAGE = 'Found'; 

exports.handler = (event, context, callback) => {
    const cf = event.Records[0].cf;

    if(cf.config.eventType === 'origin-request')
    {
        // if path ends with '/' then append INDEX_DOCUMENT before sending to S3
        if(cf.request.uri.endsWith('/'))
        {
            cf.request.uri = cf.request.uri + INDEX_DOCUMENT;
        }
        // return control to CloudFront, to send request to S3, whether or not
        // we modified it; if we did, the modified URI will be requested.
        return callback(null, cf.request);
    }
    else if(cf.config.eventType === 'origin-response')
    {
        // is the response 403 or 404?  If not, we will return it unchanged.
        if(cf.response.status.match(/^40[34]$/))
        {
            // it's an error.

            // we're handling a response, but Lambda@Edge can still see the attributes of the request that generated this response; so, we
            // check whether this is a page that should be redirected with a trailing slash appended.  If it doesn't look like an index
            // document request, already, and it doesn't end in a slash, and doesn't look like a filename with an extension... we'll try that.

            // This is essentially what the S3 web site endpoint does if you hit a nonexistent key, so that the browser requests
            // the index with the correct relative path, except that S3 checks whether it will actually work.  We are using heuristics,
            // rather than checking the bucket, but checking is an alternative.

            if(!cf.request.uri.endsWith('/' + INDEX_DOCUMENT) && // not a failed request for an index document
               !cf.request.uri.endsWith('/') && // unlikely, unless this code is modified to pass other things through on the request side
               !cf.request.uri.match(/[^\/]+\.[^\/]+$/)) // doesn't look like a filename  with an extension
            {
                // add the original error to the response headers, for reference/troubleshooting
                cf.response.headers['x-redirect-reason'] = [{ key: 'X-Redirect-Reason', value: cf.response.status + ' ' + cf.response.statusDescription }];
                // set the redirect code
                cf.response.status = HTTP_REDIRECT_CODE;
                cf.response.statusDescription = HTTP_REDIRECT_MESSAGE;
                // set the Location header with the modified URI
                // just append the '/', not the "index.html" -- the next request will trigger
                // this function again, and it will be added without appearing in the
                // browser's address bar.
                cf.response.headers['location'] = [{ key: 'Location', value: cf.request.uri + '/' }];
                // not strictly necessary, since browsers don't display it, but remove the response body with the S3 error XML in it
                cf.response.body = '';
            }
        }

        // return control to CloudFront, with either the original response, or
        // the modified response, if we modified it.

        return callback(null, cf.response);

    }
    else // this is not intended as a viewer-side trigger.  Throw an exception, visible only in the Lambda CloudWatch logs and a 502 to the browser.
    {
        return callback(`Lambda function is incorrectly configured; triggered on '${cf.config.eventType}' but expected 'origin-request' or 'origin-response'`);
    }

};

这篇关于服务索引文件而不是下载提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆