我使用S3托管一个javascript应用程序,将使用HTML5 pushStates。问题是,如果用户书签了任何url,它将不会解析为任何东西。我需要的是能够接受所有url请求,并在我的S3桶中提供根index.html,而不仅仅是进行完全重定向。然后我的javascript应用程序可以解析URL并提供适当的页面。

有没有办法告诉S3为所有URL请求服务index.html,而不是做重定向?这类似于通过提供一个index.html来设置apache来处理所有传入的请求,如本例中的https://stackoverflow.com/a/10647521/1762614。我真的希望避免仅仅为了处理这些路由而运行web服务器。从S3执行所有操作非常有吸引力。


当前回答

转到你的桶的静态网站托管设置 设置“Error document”为index.html。

其他回答

我自己也在寻找答案。S3似乎只支持重定向,你不能只是重写URL并无声地返回一个不同的资源。我正在考虑使用我的构建脚本在所有需要的路径位置简单地复制index.html。也许这对你也有用。

我做到这一点的方法如下:

在域的S3控制台的“编辑重定向规则”部分中,添加以下规则:

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>yourdomainname.com</HostName>
      <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

这将导致404错误的所有路径重定向到根域,并显示路径的散列版本。所以http://yourdomainname.com/posts将重定向到http://yourdomainname.com/#!如果/posts上没有文件。

然而,要使用HTML5的pushState,我们需要接受这个请求,并根据散列路径手动建立正确的pushState。所以把这个添加到index.html文件的顶部:

<script>
  history.pushState({}, "entry page", location.hash.substring(1));
</script>

这将获取散列并将其转换为HTML5 pushState。从这一点开始,你可以使用pushStates在你的应用程序中拥有非哈希键路径。

在2022年,Lambda函数是

函数处理程序(事件){ Var request = event.request; Var uri = request.uri; if (uri.endsWith("/")) { 请求。Uri += "index.html" } else if (!uri.includes(".")){ 请求。Uri += "/index.html" } 返回请求; }

与使用Lambda@Edge的另一个答案类似,您可以使用Cloudfront函数(截至2021年8月,它是免费层的一部分)。

我的URL结构是这样的:

React SPA托管在S3上 example.com/blog -博客托管在EC2上

由于我将博客托管在与SPA相同的域上,所以我不能使用Cloudfront 403/404错误页面使用默认错误页面的建议答案。

我的Cloudfront设置是:

设置两个源(S3和我的EC2实例通过Elastic ALB) 建立两个行为: /博客 默认(*) 创建Cloudfront函数 将Cloudfront函数设置为默认(*)行为的“查看器请求”

我使用的是基于AWS示例的Cloudfront函数。这可能并不适用于所有情况,但我的URL结构的React应用程序不包含任何..

function handler(event) {
    var request = event.request;
    var uri = request.uri;
       
    // If the request is not for an asset (js, png, etc), render the index.html
    if (!uri.includes('.')) {
        request.uri = '/index.html';
    }
      
    return request;
}

2022年6月

我已经将我的函数更新为:

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;
}

现在可以使用Lambda@Edge来重写路径

下面是一个lambda@Edge函数:

创建一个新的Lambda函数,但是使用一个已经存在的蓝图,而不是一个空白函数。 搜索“cloudfront”,并从搜索结果中选择cloudfront-response-generation。 创建函数后,将内容替换为以下内容。我还必须将节点运行时更改为10。X,因为cloudfront在撰写本文时不支持节点12。

'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 callback(null, request);
};

在您的云前行为中,您将编辑它们以在“Viewer Request”上添加对lambda函数的调用

完整教程:https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/