React路由器在AWS S3存储桶中不起作用


74

我将我的React网站build/文件夹部署到了一个AWS S3存储桶中。

如果转到www.mywebsite.com,它会起作用,如果单击a标记转到“项目”和“关于”页面,它将带我到正确的页面。但是,如果我复制并发送页面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>
);

3
我认为这不是React Router的问题,而是您的服务器不在上为您的服务器index.html以及bundle.js其他任何途径提供服务/。它需要在所有路由上提供这些文件。
Tholle

7
可能是stackoverflow.com/a/23544903/5079258的重复。您需要将错误(在这种情况下为404)重定向到根目录index.html
艾伦·弗里德曼

1
嘿@艾伦·弗里德曼。这对我行得通。
越南

Answers:


105

我不确定你是否已经解决了。我遇到过同样的问题。

这是因为AWS S3正在寻找该文件夹(项目),而您没有该文件夹。

只需将错误文档指向即可index.html

在此处输入图片说明

这对我有用。您可以在react-router中处理错误页面。


谢谢,AR。是的,由于艾伦·弗里德曼(Alan Friedman)的上述评论,我已经解决了这一问题。
越南

15
小东西。当我命中路径时,在控制台中会显示未找到404-因为我们将其重定向到错误页面。我不相信。可能有更好的方法。
Naseef AR 18年

1
是。这显然是一个hack。为了获得正确的解决方案,您可能需要添加S3重定向规则。另外,尝试从react-router使用HashRouter(而不是BrowserRouter)。这可能工作
AR Naseef

1
@LuisGouveia那你是怎么去的?你做了什么?
sumanth shetty

1
@sumanthshetty检查我对“ Amr Abu Greedah”答案的评论!祝你有美好的一天
Luis Gouveia

52

2020年5月1日更新:

由于这篇文章非常活跃,因此我需要更新答案:

因此,您可以选择几种方法来解决此问题:

  1. 您可以将index.html放在错误文档中框中(如Alan Friedman建议的那样)。
    • 转到您的存储桶(实际包含代码的存储桶-而不是用于重定向的存储桶)->属性->静态网站托管
    • 这不是“ hacky”,而是因为 react-router :它处理来自前端的请求并将用户路由到其他路由,但是总的来说,React应用程序是一个单页应用程序。
    • 如果你想服务器端反应,可以考虑使用Next.js

在此处输入图片说明

  1. 你可以把一个指定的文件错误的error.html公共您的应用程序做出反应的文件夹,并在静态网站托管错误的文件中,放于:的error.html。这也有效。我已经测试过了

  2. 使用AWS CloudFront > CloudFront分配>存储桶的分配>错误页面,然后添加所需的错误代码。如果您不使用react-router(例如下面的示例),则存储桶将响应Error 403,因此您可以使用error.html进行响应。

在此处输入图片说明

  1. 对于TypeScript,当前react-router不支持它,因此您应该考虑选项2和3。他们将6.*根据该线程在将来的版本中更新库。

2
这很hacky,也是我使用的解决方案。我不喜欢它的是404仍然发生,只是被重定向了。
ThisGuyCantEven

请注意这种情况的后果...如果您的网页包含一个src="/static/somescript.js"实际上不存在somescript.js或拒绝访问所请求脚本的位置,那么浏览器的请求将产生index.html文件的内容,而不是比JS文件要大的文件,浏览器会将其解析为JavaScript,并导致JavaScript解析错误“ <!doctype html> ...”对于CSS文件或其他资产也是如此。
jarmod

2
此解决方案影响SEO。Google排名不高的网站会抛出404。
Luis Gouveia

15

如果此S3存储桶是通过CloudFront发行版提供的

在CloudFront分发中创建一个自定义错误页面(AWS文档),该页面将404错误路由到index.html并返回200响应代码。这样,您的应用程序将处理路由。

自定义错误页面

在此处输入图片说明


2
是的,我还必须添加403
arthurakay

将合法404路由到index.html(包括图片等)是否会产生不良行为?有时您确实想拥有一个真正的
404。– cbp

这就是“您的应用程序将管理路由”的想法。每个请求都通过您的index.html(单页应用程序),并且应用程序的路由器返回相关的响应。这意味着您将路由逻辑保留在应用程序本身中,同时避免了在CloudFront中维护其他路由逻辑。这只是一个很好的技巧,它使开发人员的工作变得更轻松-作为一站式商店进行路由,无需了解任何AWS
Meir Gabay,

好吧,除了在这种情况下您的应用程序是客户端而不是服务器端。因此,作为“应用程序”,您无法再通过信号指示未找到资源。我认为您应该区分将由应用程序处理的路由和文件与将由S3或cloudfront处理的路由。
froginvasion

10

将4xx重定向到index.html可以,但是该解决方案会使您陷入许多其他问题,例如google无法抓取这些页面。请检查此链接,它通过使用S3存储桶的重定向规则解决了此问题。


4
您的回答很艰难!它应该是被接受的答案,因为被接受的答案是次优的,并且对SEO的影响非常不便(因为Google不喜欢返回404的网站)。如果有人在搜索相当于Microsoft世界的@Amr Abu Greedah,我建议检查以下答案:stackoverflow.com/a/50767709/3231884
Luis Gouveia

万一使用xml格式失败,请尝试使用json版本作为重定向规则。这就是我为使此解决方案对我
尼克

6

案例使用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;无论哪种方式,最好都处理两个响应代码)。


这对我有用。它与stackoverflow.com/a/52343542/2624935相同,但对于云端
Pnar Sbi Wer

这工作了!经过大量关于此的文章403是缺少的链接-谢谢
Chris Webb

与文章所说的相反,这不仅适用于html页面。任何404(包括图片等)都将重定向index.html,这非常难看。
cbp

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文档中提供了有关网站终端节点的更多信息。


这样可行。但是,为什么您需要云服务并从SSL和多区域分布中受益呢?
帕特里克·巴索

1

为什么会发生

您的问题是您希望将责任传递给您的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应用有自己的位置而不干扰其他内容,则此配置是最简单的。


所以这意味着我每次在React中点击链接时都会收到一个http请求?
伊泰·莫阿夫

1
@ ItayMoav-Malimovka不,不是这样。仅当您在初始URL中输入应用程序/类型时,它才会发生。服务器在这里决定向客户端服务器的内容-在这种情况下是React应用。从那时起,React路由器将接管服务器,在服务器不知道的情况下更改显示的URL,历史记录等。
Gegenwind

6
这是关于s3上的路由。之间没有服务器
mithril_knight

1

尽管使用了已接受的答案中所述的配置,但是我仍然遇到了此问题,但是如果仍然出现403错误,并且您正在使用AWS Cloudflare Manager,则可以在分发设置的“错误页面”选项卡中创建错误页面。 ,具有以下配置:

Error Code: 404,
Customize Error Response: Yes, 
Response Page Path: /index.html, 
HTTP Response Code: 200

错误页面配置的图片将路由处理传递给浏览器路由器

尽管我对适当的服务器管理员一无所知,但这对我还是有用的,希望有人能告诉我这是否是主要问题,是否偶然。


403 =禁止。您确定您的存储桶或对象是公开的吗?
越南

1
我做了与@worc相同的操作:CloudFront>错误页面>创建自定义错误响应> 403或404,具体取决于您的错误>自定义错误响应:是>响应页面路径:/index.html> HTTP响应代码:200
SvenMöhring

您将在Cloud Front中遇到来自Cloudfront的错误X缓存错误
chemitaxis


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。


看起来像一个快速而整洁的解决方案。但是要当心!在他们的文档中,他们鼓励改为配置您的服务器:“重要说明:哈希历史记录不支持location.key或location.state。在以前的版本中,我们尝试对行为进行伪装,但存在无法解决的极端情况。任何需要这种行为的代码或插件将不起作用。由于此技术仅用于支持旧版浏览器,因此我们建议您将服务器配置为与<BrowserHistory>一起使用。” reactrouter.com/web/api/HashRouter
wojjas

0

我正在使用NextJS并遇到相同的问题。我的解决方案是检查路由信息并推送不适合的信息。

const router = useRouter();
useEffect(() => {
    if (!router.pathname.startsWith(router.asPath)) {
      router.push(router.asPath);
    }
  });

除了将错误页面路由到index.html之外,无需在S3端进行任何修改。


-1

按照先前的答案,解决问题的最佳方法是:重新定义后备策略。如果您想了解有关客户端路由和服务器端的更多信息,特别是有关React JS中不同路由方法的信息,请查看本文


该解决方案似乎遇到了两个问题:1)尽管正确返回了页面内容,但http响应代码仍为404。2)它将捕获404对图像等内容的请求并将其路由到index.html
cbp

好的,如果有问题,我建议您使用重定向规则Redirect Rules。错误页面配置下一行。 示例3:从文档重定向HTTP错误将是一个很好的开始。在这一<Condition>部分中,我们可以添加<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>。并且所有请求都应该为301。–
Val
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.