我使用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执行所有操作非常有吸引力。
现在可以使用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;
}
其他人提到的基于S3/Redirect的方法有一些问题。
多重重定向发生在应用程序的路径被解析时。例如:www.myapp.com/path/for/test被重定向为www.myapp.com/#/path/for/test
由于您的SPA框架的操作,当“#”出现和消失时,url栏中有一个闪烁。
seo会受到影响,因为——‘嘿!这谷歌迫使他的手重定向
Safari对你的应用程序的支持值得一试。
解决方案是:
Make sure you have the index route configured for your website. Mostly it is index.html
Remove routing rules from S3 configurations
Put a Cloudfront in front of your S3 bucket.
Configure error page rules for your Cloudfront instance. In the error rules specify:
Http error code: 404 (and 403 or other errors as per need)
Error Caching Minimum TTL (seconds) : 0
Customize response: Yes
Response Page Path : /index.html
HTTP Response Code: 200
For SEO needs + making sure your index.html does not cache, do the following:
Configure an EC2 instance and setup an nginx server.
Assign a public ip to your EC2 instance.
Create an ELB that has the EC2 instance you created as an instance
You should be able to assign the ELB to your DNS.
Now, configure your nginx server to do the following things: Proxy_pass all requests to your CDN (for index.html only, serve other assets directly from your cloudfront) and for search bots, redirect traffic as stipulated by services like Prerender.io
我可以提供更多关于nginx设置的细节,请留下一张便条。经历了惨痛的教训。
一旦云前端分发更新。使您的云前缓存失效一次,使其处于原始模式。
在浏览器中点击url,一切都应该是好的。
我做到这一点的方法如下:
在域的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在你的应用程序中拥有非哈希键路径。