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

时间:2018-07-07 00:21:00

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

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

14 个答案:

答案 0 :(得分:17)

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

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

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

enter image description here

这对我有用。您可以在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响应代码。 这样,您的应用程序将处理路由。

自定义错误页面

enter image description here

答案 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

enter image description here

答案 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.html404 添加了错误页面为 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

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

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

答案 12 :(得分:0)

以下配置已解决 enter image description here

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

答案 13 :(得分:-1)

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