我使用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执行所有操作非常有吸引力。
如果你在这里寻找与React路由器和AWS Amplify控制台一起工作的解决方案,你已经知道你不能直接使用CloudFront重定向规则,因为Amplify控制台不会为应用程序公开CloudFront Distribution。
然而,解决方案非常简单-你只需要在Amplify控制台中添加一个重定向/重写规则,就像这样:
查看以下链接获取更多信息(以及截图中的复制友好规则):
https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa
https://github.com/aws-amplify/amplify-console/issues/83
现在可以使用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/
与使用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;
}