代码之家  ›  专栏  ›  技术社区  ›  Costa Michailidis

提供索引文件而不是下载提示

  •  1
  • Costa Michailidis  · 技术社区  · 6 年前

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

    example.com/directory example.com/directory/

    那个带着 / 最后错误地提示浏览器下载一个零字节文件,文件名带有随机哈希。如果没有斜线,它会返回我的404页。

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

    如果有一种方法我应该这样做,太好了!这正是我所希望的,但如果不是,我可能会尝试使用lambda@edge进行重定向。不管怎样,我还是需要在其他情况下使用它,所以关于如何从lambda@edge执行301或302重定向的一些说明也会很有帮助:)

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

    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错误路由。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Michael - sqlbot    6 年前

    S3只在启用并使用bucket的网站宿主功能时,通过指向bucket的网站宿主端点,提供自动索引文档。 ${bucket}.s3-website.${region}.amazonaws.com 而不是bucket的通用rest端点, ${bucket}.s3.amazonaws.com .

    网站终结点和REST终结点具有 numerous differences 包括这个。

    您看到这些0字节的对象键文件以 / 这是因为您正在使用S3控制台或另一个实际创建0字节对象的实用程序在bucket中创建文件夹对象。一旦文件夹中有对象,就不需要它们——但是它们是在S3控制台中显示空文件夹的唯一方法,该控制台显示名为 foo/ 作为名为 foo ,即使没有其他键前缀为的对象 福奥/ . 它是控制台中文件夹层次结构的可视化仿真的一部分,即使S3中的对象从来不是真正的“在”文件夹中。

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

    原产地请求 触发器可以在检查CloudFront缓存之后、将请求发送到源站之前检查和修改请求。我们用这个来检查一条以 / 追加 index.html 如果我们找到了。

    原产地响应 触发器可以在将响应写入CloudFront缓存之前检查并可能修改响应。原始响应触发器还可以检查在生成响应的请求之前的原始请求。我们使用这个来检查响应是否是一个错误。如果是,原始请求会 似乎是针对索引文档或文件(具体来说,在路径中的最后一个斜杠之后,“文件”至少有一个字符,后跟一个点,后跟至少一个字符——如果是这样,那可能是“文件”)。如果这两者都不是,我们将重定向到原始路径加上最终路径。 / 我们追加的。

    源请求和源响应触发火灾 只有 缓存未命中。当缓存命中时,两个触发器都不会触发,因为它们位于CloudFront的源端——缓存的后端。可以从缓存提供服务的请求从缓存提供服务,因此不会调用触发器。

    下面是用node.js 8.10编写的lambda@edge函数。这一个lambda函数修改其行为,使其根据上下文作为源请求或源响应。在lambda中发布版本后,将该版本的ARN与CloudFront缓存行为设置关联为 二者都 源请求和源响应触发器。

    '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'`);
        }
    
    };
    
        2
  •  1
  •   Ronnie Smith    6 年前

    这种类型的行为通常由HTTP(S)头数据控制/引起,特别是 Content-Type 客户收到的。

    Inspect the header 尝试调整从服务器返回的内容。这将导致你的解决方案。

    1. 在chrome中,访问一个URL,右键单击,选择Inspect以打开开发人员工具。
    2. 选择网络选项卡。
    3. 重新加载页面,选择左侧面板上的任何HTTP请求,HTTP头将显示在右侧面板上。