我使用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/
既然问题仍然存在,我想我提出另一个解决方案。
我的情况是,我想在合并之前自动将所有拉请求部署到s3进行测试,使它们可以在[mydomain]/pull-requests/[pr number]/上访问
(例如www.example.com/pull-requests/822/)
据我所知,没有s3规则的场景允许在一个桶中使用html5路由有多个项目,所以上面大多数投票建议适用于根文件夹中的项目,不适用于自己子文件夹中的多个项目。
所以我把我的域指向我的服务器,在那里遵循nginx配置做的工作
location /pull-requests/ {
try_files $uri @get_files;
}
location @get_files {
rewrite ^\/pull-requests\/(.*) /$1 break;
proxy_pass http://<your-amazon-bucket-url>;
proxy_intercept_errors on;
recursive_error_pages on;
error_page 404 = @get_routes;
}
location @get_routes {
rewrite ^\/(\w+)\/(.+) /$1/ break;
proxy_pass http://<your-amazon-bucket-url>;
proxy_intercept_errors on;
recursive_error_pages on;
error_page 404 = @not_found;
}
location @not_found {
return 404;
}
它尝试获取文件,如果没有找到,则假设它是html5路由并尝试。如果你在angular的404页面中没有找到路由,你将永远不会到达@not_found,而会返回angular 404页面而不是not found files,这可以通过在@get_routes中添加If规则来修复。
我不得不说我在nginx配置和使用regex方面感到不太舒服,我得到了这个工作,经过了一些试验和错误,所以虽然这是有效的,但我相信有改进的空间,请分享你的想法。
注意:如果在s3配置中有重定向规则,请删除它们。
顺便说一下,在Safari中工作
其他人提到的基于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,一切都应该是好的。
与使用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;
}