我将我的React网站build/
文件夹部署到了一个AWS S3存储桶中。
如果我转到www.mywebsite.com
,它会起作用,如果我单击a
标记,转到Project和About页面,它将带我到正确的页面。
但是,如果我复制并发送页面URL或直接转到诸如www.mywebsite.com/projects
之类的链接,它将返回404。
这是我的App.js
代码:
const App = () => (
<Router>
<div>
<NavBar/>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/projects" component={Projects}/>
<Route exact path="/about" component={About}/>
<Route component={NoMatch}/>
</Switch>
</div>
</Router>
);
答案 0 :(得分:17)
我不确定您是否已经解决它。我有同样的问题。
这是因为AWS S3正在寻找该文件夹(项目)供您使用,而您没有该文件夹。
只需将错误文档指向index.html
。
这对我有用。您可以在react-router中处理错误页面。
答案 1 :(得分:9)
将4xx重定向到index.html可以,但是该解决方案会使您陷入许多其他问题,例如google无法抓取这些页面。 请检查this link,它通过对S3存储桶使用重定向规则解决了此问题。
答案 2 :(得分:8)
回答以结束问题。感谢Alan Friedman的上述评论,我已经解决了这个问题:
您需要将错误(在这种情况下为404)重定向到根index.html – 7月7日0:34
答案 3 :(得分:5)
这个问题已经有了几个很好的答案。尽管这个问题现在已经很老了,但我今天遇到了这个问题,所以我觉得这个答案可能会有所帮助。
S3有两种端点,如果遇到此错误,则可能已在CloudFront分布的“原始域名”字段中直接选择了S3存储桶作为端点。
这看起来像:bucket-name.s3.amazonaws.com
,并且是完全有效的端点。实际上,AWS似乎确实希望这是默认行为。该条目将在创建CloudFront发行版时的下拉列表中。
但是,执行此操作然后设置错误页面可能无法解决您的问题。
但是,S3具有专用的网站端点。可以从S3存储桶>属性>静态网站托管访问。 (您将在顶部看到链接)。
您应该使用此链接,而不是CloudFront中出现的原始自动填充的链接。您可以在创建发行版时将其放入其中,也可以在创建发行版后从选项卡Origins和Origins Groups中进行编辑,然后使缓存无效。
此链接看起来像:bucket-name.s3-website.region-name.amazonaws.com
。
一旦这种情况传播和改变,那么就可以解决您的问题。
tl; dr:不要在CloudFront中使用默认的S3端点。请改用S3网站终结点。您的原始域应如下所示:my-application.s3-website.us-east-1.amazonaws.com
,而不像my-application.s3.amazonaws.com
。
有关网站终端节点的更多信息,请参阅AWS文档here。
答案 4 :(得分:3)
为什么会发生
您的问题是您想将责任传递给路由到您的react app / javascript。该链接将起作用,因为react可以侦听链接单击并仅在浏览器URL栏中更新路由。但是,如果您未加载脚本(index.html和bundle.js或应用程序代码所在的位置)的位置,则JavaScript永远不会加载,也没有机会处理请求。取而代之的是,服务器运行的任何内容都会处理请求,查看该位置是否有资源,并返回404错误或发现的其他错误。
解决方案
如评论中所述,这就是为什么您需要将404错误重定向到放置应用程序的确切位置的原因。这不是特定于Amazon的,这是设置您的react应用程序的一般要求。
要解决此问题,您需要找出什么处理服务器上的路由以及如何配置它。例如,如果您有Apache服务器,则.htaccess文件可以解决以下问题:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
此文件使服务器将未找到的错误重定向到index.html。请记住,这可能会影响服务器上的其他路由规则,因此,如果您的react应用有自己的位置而不干扰其他内容,则此配置是最简单的。
答案 5 :(得分:2)
尽管使用已接受答案中所述的配置,但我仍然遇到此问题,但是如果仍然出现403错误,并且您正在使用AWS Cloudflare Manager,则可以在以下页面的“错误页面”选项卡中创建错误页面分发设置,具有以下配置:
Error Code: 404,
Customize Error Response: Yes,
Response Page Path: /index.html,
HTTP Response Code: 200
Pic of Error Page Config to pass route handling to browser router
这对我有用,尽管我对适当的服务器管理员一无所知,希望有人告诉我这是否是一个重大问题,如果偶然的话。
答案 6 :(得分:2)
如果从CloudFront distribution为该S3存储桶提供服务:
在CloudFront分发中创建一个custom error page (AWS Docs),将404错误路由到index.html并返回200响应代码。 这样,您的应用程序将处理路由。
答案 7 :(得分:1)
将Cloudfront应用于S3:
https://hackernoon.com/hosting-static-react-websites-on-aws-s3-cloudfront-with-ssl-924e5c134455
3b)AWS CloudFront -错误页面 创建CloudFront分配后,其状态为“进行中”时,请进入“错误页面”选项卡。使用自定义错误响应处理响应代码404和403。
Google建议您进行1周或604800秒的缓存。 我们在这里所做的是设置CloudFront来处理丢失的html页面,这通常在用户输入无效路径时发生,特别是在用户刷新除根路径之外的路径时发生。
发生这种情况:
CloudFront将寻找S3存储桶中不存在的文件;存储桶中只有1个html文件,对于像该项目示例这样的单页应用程序,这就是index.html 将会返回404响应,而我们的自定义错误响应设置将劫持它。我们将返回200响应代码和index.html页面。 React路由器将与index.html文件一起加载,它将查看url并呈现正确的页面而不是根路径。该页面将在TTL持续时间内被缓存到所有查询路径的请求中。 为什么我们还需要处理403?这是因为,Amazon S3对于不存在的资产返回了此响应代码,而不是404。例如,一个https://yourdomain.com/somewhere的网址将寻找一个不存在的文件(不带扩展名)。
PS。它曾经返回404,但现在似乎返回了403;无论哪种方式,最好都处理两个响应代码。
答案 8 :(得分:0)
通过托管静态更新s3的配置,默认使用index.html进行更新 enter image description here
添加带有错误页面的CloudFront
404 error-> index.html->status 200
答案 9 :(得分:0)
我通过使用HashRouter
而不是Router
来解决了该问题
import { Switch, Route, HashRouter } from 'react-router-dom';
const App = () => (
<HashRouter>
<div>
<NavBar/>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/projects" component={Projects}/>
<Route exact path="/about" component={About}/>
<Route component={NoMatch}/>
</Switch>
</div>
</HashRouter>
);
该应用可以通过以下方式访问
https://your-domain.s3.amazonaws.com/index.html?someParam=foo&otherPram=bar/#/projects
在本地主机上,例如
https://localhost:3000/?someParam=foo&otherPram=bar/#/projects
无需更改S3。
答案 10 :(得分:0)
我正在使用NextJS并遇到相同的问题。 我的解决方案是检查路由信息并在不适合的情况下进行推送。
const router = useRouter();
useEffect(() => {
if (!router.pathname.startsWith(router.asPath)) {
router.push(router.asPath);
}
});
除了将错误页面路由到index.html之外,无需在S3端进行任何修改
答案 11 :(得分:0)
这个帖子对我很有帮助。我知道这是旧的,但是,我想添加一个最终对我有用的 aws-cdk
代码片段。我的用例需要我使用 aws-cdk
,因此,如果您期待基于 aws-cdk
的解决方案,我会在此处添加它。
代码片段将 index.html
添加为 s3 和 cloudfront 中的错误页面。特别是对于 cloudfront,我为 /index.html
和 404
添加了错误页面为 403
,响应为 200
// imports...
// import * as cdk from '@aws-cdk/core';
// import * as s3 from '@aws-cdk/aws-s3';
// import * as cloudfront from '@aws-cdk/aws-cloudfront';
// following code snippet has to be added in a
// class which extends to a Construct or a Stack
const bucket = new s3.Bucket(this, '<Specify a name>', {
bucketName: '<add your bucket name>',
websiteIndexDocument: 'index.html',
websiteErrorDocument: 'index.html',
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
removalPolicy: cdk.RemovalPolicy.DESTROY, // edit it according to your use case, I'll change it though
autoDeleteObjects: true,
});
const cloudFrontOAI = new cloudfront.OriginAccessIdentity(this, 'OAI');
const distribution = new cloudfront.CloudFrontWebDistribution(this, props?.stackName + 'AbcWebsiteDistribution', {
defaultRootObject: "index.html",
errorConfigurations: [{
errorCode: 404,
responsePagePath: "/index.html",
responseCode: 200
}, {
errorCode: 403,
responsePagePath: "/index.html",
responseCode: 200
}],
originConfigs: [
{
s3OriginSource: {
s3BucketSource: bucket,
originAccessIdentity: cloudFrontOAI,
originPath: "/artifacts" // change this based on your use case
},
behaviors: [{ isDefaultBehavior: true }]
}
]
})
bucket.grantRead(cloudFrontOAI.grantPrincipal);
从这个线程中真正帮助我的答案是:
https://stackoverflow.com/a/56655629/6211961
答案 12 :(得分:0)
答案 13 :(得分:-1)
按照先前的答案,解决问题的最佳方法是:重新定义后备策略。 如果您想了解有关客户端路由与服务器端的更多信息,尤其是有关React JS中不同路由方法的信息,请查看this article。