【问题标题】:react router doesn't work in aws s3 bucket反应路由器在 aws s3 存储桶中不起作用
【发布时间】:2018-12-15 13:40:01
【问题描述】:

我将我的 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>
);

【问题讨论】:

  • 我认为这不是 React Router 的问题,而是您的服务器没有在 / 以外的任何其他路由上为您的 index.htmlbundle.js 提供服务。它需要在所有路由上提供这些文件。
  • stackoverflow.com/a/23544903/5079258 的可能欺骗。您需要将错误(在这种情况下为 404)重定向到根 index.html

标签: javascript reactjs amazon-web-services amazon-s3


【解决方案1】:

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

这是因为 AWS S3 正在寻找您没有的文件夹(项目)来提供服务。

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

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

【讨论】:

  • 小事。当我点击路径时,在控制台中显示 404 not found - 因为我们将其重定向到错误页面。我不相信。可能有更好的方法。
  • 是的。这显然是一个 hack。对于正确的解决方案,您可能需要添加 S3 重定向规则。另外,尝试使用 react-router 中的 HashRouter(而不是 BrowserRouter)。这可能有效
  • 虽然此解决方案有效,但它会影响 SEO。谷歌将你的网站排名比其他不抛出那么多 404 的网站更差。我很难学到这一点。
  • @LuisGouveia 你当时是怎么做的?你做了什么?
  • @sumanthshetty 检查我对“Amr Abu Greedah”答案的评论!祝你有美好的一天
【解决方案2】:

2020 年 5 月 1 日更新:

由于这个帖子很活跃,我需要更新答案:

所以你有几个选项来解决这个问题:

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

  1. 您可以将指定的错误文件 error.html 放入 React 应用的 public 文件夹和 静态网站托管 >:错误文档框,放入:error.html。这也有效。我已经测试过了。

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

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

【讨论】:

  • 这很hacky,也是我使用的解决方案。我不喜欢的是 404 仍然发生,它只是被重定向。
  • 请注意这样做的一个后果...如果您的网页包含 src="/static/somescript.js" 其中 somescript.js 实际上不存在,或者拒绝访问所请求的脚本,则浏览器的请求将产生 index.html 文件而不是 JS 文件的内容,并且将被浏览器解析为 JavaScript 并导致 JavaScript 解析错误“ ...”对于 CSS 文件或其他资产类似。
  • 此解决方案会影响 SEO。 Google 不会对抛出 404 的网站进行排名。
  • 如何为错误页面添加自定义标题? stackoverflow.com/questions/69183284/…
【解决方案3】:

如果此 S3 存储桶由 CloudFront distribution 提供服务:

在 CloudFront 分配中创建一个custom error page (AWS Docs),将 404 错误路由到 index.html 并返回 200 响应代码。 这样您的应用程序将处理路由。

自定义错误页面

【讨论】:

  • 是的,我也必须添加 403
  • 这不会有将合法 404 路由到 index.html 的不良行为,包括图像等?有时你确实想要一个真正的 404。
  • 这就是“您的应用程序将管理路由”背后的想法。每个请求都通过您的 index.html(单页应用程序),并且您的应用程序的路由器返回相关响应。这意味着您将路由逻辑保留在应用程序本身中,同时避免在 CloudFront 中维护另一个路由逻辑。这只是一个很好的技巧,它使开发人员的生活更轻松 - 路由作为一站式服务,无需了解 AWS
  • 好吧,除了在这种情况下您的应用程序是客户端的,而不是服务器端的。因此,作为“应用程序”,您不能再发出未找到资源的信号。我认为您应该区分将由应用程序处理的路由和文件以及将由 S3 或 cloudfront 处理的路由。
  • 是的,它也适用于我
【解决方案4】:

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

【讨论】:

  • 你的答案很震撼!这应该是公认的答案,因为公认的答案是次优的,并且对 SEO 有非常不便的影响(因为 google 不喜欢返回 404 的网站)。如果有人正在搜索微软世界的@Amr Abu Greedah,我建议检查以下答案:stackoverflow.com/a/50767709/3231884
  • 以防万一使用 xml 格式失败,请尝试使用 json 版本的重定向规则。这就是我必须为这个解决方案为我工作而做的事情
  • 绝对是正确的答案。我一直在寻找这种方式。
  • 解决index.html加载相关css/js文件的问题
【解决方案5】:

使用 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 页面。 将与 index.html 文件一起加载的 React 路由器将查看 url 并呈现正确的页面而不是根路径。对于查询路径的所有请求,此页面将在 TTL 期间缓存。 为什么我们还需要处理 403?这是因为 Amazon S3 为不存在的资产返回此响应代码,而不是 404。例如,https://yourdomain.com/somewhere 的 url 将寻找一个不存在的名为某处(无扩展名)的文件。

附言。它曾经返回404,但现在似乎返回403;无论哪种方式,最好同时处理两个响应代码)。

【讨论】:

  • 这对我有用。它与stackoverflow.com/a/52343542/2624935 相同,但用于云端
  • 这成功了!通过大量关于此的文章,403 是缺少的链接 - 谢谢
  • 与文章所说的相反,这不仅仅适用于 html 页面。任何 404,包括图片等,都会重定向 index.html,相当难看。
【解决方案6】:

这个问题已经有几个很好的答案。虽然这个问题现在很老了,但我今天遇到了这个问题,所以我觉得这个答案可能会有所帮助。

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

【讨论】:

  • 那行得通。但是,您为什么需要云端并从 SSL 和多区域分发中受益?
【解决方案7】:

以下配置已解决

更新了相关云前端分发中的错误页面,自定义错误响应从 http 状态代码 404-not-found 到响应页面路径处的代码 200-OK 为 / 且生存时间接近于零

【讨论】:

    【解决方案8】:

    这个帖子对我很有帮助。我知道这是旧的,但是,我想添加一个 aws-cdk 代码 sn-p 最终对我有用。我的用例需要我使用aws-cdk,因此,如果您期待基于aws-cdk 的解决方案,我将在此处添加它。

    代码 sn-p 在 s3 和 cloudfront 中添加 index.html 作为错误页面。特别是对于云端,我为404403 添加了错误页面为/index.html,响应为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

    https://stackoverflow.com/a/58978355/6211961

    https://stackoverflow.com/a/64201582/6211961

    【讨论】:

    • 谢谢,我也在使用 cdk,正在寻找这个
    【解决方案9】:

    为什么会发生

    您的问题是您希望将责任传递给您的反应应用程序/javascript。该链接将起作用,因为 react 可以侦听链接单击并简单地更新浏览器 URL 栏中的路由。但是,如果您去的位置没有加载您的脚本(index.html 和 bundle.js 或您的应用程序代码所在的任何位置),则 JavaScript 永远不会加载并且没有机会处理请求。相反,无论您的服务器运行什么,都会处理该请求,查看此位置是否有资源,然后返回 404 错误或发现的任何其他错误。

    解决方案

    正如 cmets 中所述,这就是您需要将 404 错误重定向到您的应用所在的确切位置的原因。这不是亚马逊特有的,它是设置您的反应应用程序的一般要求。

    要解决此问题,您需要了解在您的服务器上处理路由的内容以及如何配置它。例如,如果你有一个 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 请求?
    • @ItayMoav-Malimovka 不,事实并非如此。仅当您在初始 URL 中输入应用程序/类型时才会发生这种情况。在这里,服务器决定向客户端提供什么服务 - 在本例中是 React 应用程序。从那时起,React 路由器接管,在服务器不知道的情况下更改显示的 URL、历史记录等。
    • 这是关于 s3 上的路由。中间没有服务器
    【解决方案10】:

    尽管使用了接受的答案中描述的配置,但我遇到了这个问题,但如果您仍然收到 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

    这对我有用,尽管我对适当的服务器管理员一无所知,希望有人会告诉我这是否是一个重大问题,如果是偶然的。

    【讨论】:

    • 403 = 禁止。您确定您的存储桶或对象是公开的吗?
    • 我做了与@worc 相同的操作:CloudFront > 错误页面 > 创建自定义错误响应 > 403 或 404,取决于您的错误 > 自定义错误响应:是 > 响应页面路径:/index.html > HTTP 响应代码:200
    • 您将在云端遇到来自云端的错误 x-cache 错误
    【解决方案11】:

    使用静态托管更新 s3 的配置,默认使用 index.html enter image description here

    添加带有错误页面的 CloudFront

    404 error-> index.html->status 200
    

    enter image description here

    【讨论】:

      【解决方案12】:

      在这个线程中有一些很好的答案,主要是关于使用重定向规则配置您的 S3 存储桶。虽然这也适用于我的用例,它通常通过 CloudFront 使用 React Router 托管 React 单页应用程序,并将 S3 配置为 Origin,但鉴于最近发布的一种新功能,我决定尝试不同的方法, CloudFront 函数。主要思想是在 URL 到达 CloudFront 缓存之前重写 URL,以便在客户端由 React Router 创建的 URL 被重写以指向应用程序域根。

      您可以在此处阅读有关 CloudFront 函数的更多信息: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html

      主要思想是使用 CloudFront 函数为任何不针对静态文件(即 .js、.CSS、.html 等)的请求重写请求 Uri,并使其指向 /index.html文件。此函数将作为查看器请求触发器的一部分运行,并在 CloudFront 检查请求的对象是否在 CloudFront 缓存中之前运行。这将导致客户端发送的任何由 React 路由器生成的 Uri 在从源服务器请求内容之前被重写,因此不需要在 S3 上进行任何进一步的重定向。同时,请求但在源上不再存在的文件将按预期返回 404,而所有其他静态内容将按请求提供。

      这是我的 CloudFront 函数的样子:

      function handler(event) {
        var request = event.request;
      
        if (!request.uri.includes('.')) {
          request.uri = "/index.html";
          request.querystring = {}
        }
      
        return request;
      }
      

      您可以根据自己的喜好使 URL 重写规则变得复杂,但令人惊讶的是,这小段代码非常适合我的用例。此外,与 Lambda@Edge 函数不同,CloudFront 函数更轻量级,允许您通过 AWS 控制台进行几乎实时的实验,方法是在其中更改函数代码、对其进行测试并在几秒钟内部署它。但是,它们具有某些语言限制,因此不要期望支持所有 JavaScript 语言功能。此页面记录了可供您使用的内容:

      https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-javascript-runtime-features.html

      【讨论】:

        【解决方案13】:

        我通过使用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&amp;otherPram=bar/#/projects

        在本地主机上 https://localhost:3000/?someParam=foo&amp;otherPram=bar/#/projects

        不需要对 S3 进行任何更改。

        【讨论】:

        • 看起来是一个快速而简洁的解决方案。但要小心!在他们的文档中,他们鼓励配置您的服务器:“重要说明:哈希历史不支持 location.key 或 location.state。在以前的版本中,我们试图调整该行为,但存在我们无法解决的边缘情况。任何需要此行为的代码或插件将不起作用。由于此技术仅用于支持旧版浏览器,因此我们鼓励您将服务器配置为使用 。” reactrouter.com/web/api/HashRouter
        【解决方案14】:

        我正在使用 NextJS 并且遇到了同样的问题。 我的解决方案是检查路由信息,如果不合适就推送。

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

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

        【讨论】:

        • 所以这在运行您的纯静态 Next.js 应用程序时是否有效?换句话说,用户会去/projects,比如说让你去index.html,然后你会找到/projects,因为那是router.asPath?
        【解决方案15】:

        根据之前的答案,解决问题的最佳方法:重新定义后备策略。 如果您想了解更多关于客户端路由与服务器端的信息,尤其是 React JS 中不同的路由方法,请查看this article

        【讨论】:

        • 这个解决方案似乎有几个问题:1)虽然页面内容返回正确,但http响应代码仍然是404。2)它将捕获对图像等内容的404请求和将它们路由到 index.html
        • 好电话,如果有问题,我建议使用重定向规则,Redirect Rules。错误页面配置下方的一行。 示例 3:从文档中重定向 HTTP 错误 将是一个很好的起点。在&lt;Condition&gt; 部分,我们可以添加类似&lt;HttpErrorCodeReturnedEquals&gt;404&lt;/HttpErrorCodeReturnedEquals&gt; 的内容。并且所有请求都应该是 301。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-24
        • 2021-01-02
        • 1970-01-01
        • 2018-01-06
        • 2018-01-26
        • 2015-11-27
        相关资源
        最近更新 更多