反应路由器在aws s3存储桶中不起作用

Vie*_*iet 24 javascript amazon-s3 amazon-web-services reactjs

我将React网站build/文件夹部署到AWS S3存储桶中.

如果我去www.mywebsite.com,它可以工作,如果我点击a标签去项目和关于页面,它会引导我到正确的页面.但是,如果我复制并发送页面网址或直接转到类似的链接: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>
);
Run Code Online (Sandbox Code Playgroud)

A.R*_*eef 43

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

这是因为AWS S3正在寻找您没有的文件夹(项目).

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

在此输入图像描述

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

  • 尽管此解决方案有效,但它会影响 SEO。Google 会将您的网站排名比其他不会抛出 404 错误的网站更差。我经过惨痛的教训才学到这个。 (4认同)
  • 小东西。当我命中路径时,在控制台中会显示未找到404-因为我们将其重定向到错误页面。我不相信。可能有更好的方法。 (3认同)
  • @sumanthshetty 检查我对“Amr Abu Greedah”答案的评论!祝你今天过得愉快 (2认同)

Mei*_*bay 29

如果此 S3 存储桶由CloudFront 分配提供

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

自定义错误页面

在此处输入图片说明

  • 是的,我还必须添加 403 (6认同)
  • 这是否会产生将合法 404 路由到 index.html(包括图像等)的不良行为?有时您确实希望拥有真正的 404。 (2认同)

小智 20

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

  • 你的答案很震撼!它应该是被接受的答案,因为被接受的答案是次优的,并且对 SEO 有非常不便的影响(因为谷歌不喜欢返回 404 的网站)。如果有人在搜索 @Amr Abu Greedah 的 Microsoft 世界等效内容,我建议检查以下答案:/sf/answers/3553739661/ (5认同)

Kon*_*los 18

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

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

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

我的 CloudFront 函数如下所示:

function handler(event) {
  var request = event.request;

  if (!request.uri.includes('.')) {
    request.uri = "/index.html";
    request.querystring = {}
  }

  return request;
}
Run Code Online (Sandbox Code Playgroud)

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

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


Pra*_*yas 16

以下配置已解决 在此输入图像描述

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


Vie*_*iet 12

回答以结束问题。多亏了艾伦·弗里德曼(Alan Friedman)的上述评论,我已经解决了这个问题:

您需要将错误(在本例中为404)重定向到根index.html – 7月7日,0:34

  • 这是非常hacky的,但也是我使用的解决方案。我不喜欢的是 404 仍然会发生,它只是被重定向了。 (3认同)
  • 该解决方案会影响 SEO。Google 对抛出 404 错误的网站排名不佳。 (3认同)

小智 10

100% 工作并经过测试,可在 S3 Bucket 中托管 React 等 SPA 网站并修复 404 子页面问题

  1. 登录亚马逊控制台
  2. 搜索云前线
  3. 选择您的发行版
  4. 选择错误页面选项卡并单击创建自定义错误响应 在此输入图像描述
  5. 在此创建响应规则 在此输入图像描述
  6. 保存错误规则

你已经完成了!


小智 9

案例使用 Cloudfront 到 S3:

https://hackernoon.com/hosting-static-react-websites-on-aws-s3-cloudfront-with-ssl-924e5c134455

3b) AWS CloudFront?—?Error Pages 创建 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 的网址 将寻找一个不存在的名为某处(没有扩展名)的文件。

附注。以前是返回404,现在好像是返回403;无论哪种方式,最好都处理两个响应代码)。


Col*_*dal 9

这里有很多答案,所以我想我应该对迄今为止现有的答案进行调查,并比较各种方法的优缺点。

方法 描述 优点 缺点 答案
云前功能 使用 AWS CloudFront 函数将请求写入 SPA 的根文档,例如index.html 没有抛出错误,没有重定向,显然有利于 SEO。AWS 在他们的一份文档中建议了这种方法。 额外费用(尽管在撰写本文时,免费套餐允许每月免费 200 万次调用,之后每百万次调用仅收取 10c)。需要部署/管理的额外基础设施。 公斤
作为网站托管 配置 S3 存储桶来托管网站,而不是 REST API。 当以这种方式配置时,路由由 S3 自动处理。 无法使用 Orign Access Identity。相反,S3 端点通过 HTTP 公开,您需要使用自定义标头来限制访问,这更加复杂。 前值
错误重定向(404 和 403) 绝大多数答案似乎都提供了一些这种味道。这个想法是允许 404 或 403 错误发生,但随后返回index.html(或任何 SPA 根文档)作为错误页面。 易于实施。 每次客户端尝试访问非根 URL 时都会导致客户端重定向。显然这对 SEO 不利。 AR , V , MG , PB , K , KS
URL 哈希/Hashbang 一些解决方案涉及使用 URL 中的哈希值来路由子页面。 无需重定向,也无需支付额外的 AWS 资源费用。 这些方法似乎存在问题 - 请参阅此处。有些人认为 URL 中的哈希值很丑陋;似乎确实有办法减轻这种情况,但这涉及一些额外的复杂性。 AA , B

注意:我的这个答案是基于我在其他答案中读到的内容。除了“CloudFront Function”方法之外,我还没有完全测试任何方法,我可以确认该方法有效。


小智 8

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

S3 有两种端点,如果您遇到此错误,您可能已直接选择 S3 存储桶作为 CloudFront 分配的源域名字段中的端点。

这看起来像:bucket-name.s3.amazonaws.com并且是一个完全有效的端点。事实上,AWS 似乎确实希望这是默认行为;此条目将在您创建 CloudFront 分配时的下拉列表中。

但是,执行此操作然后设置错误页面可能会也可能不会解决您的问题。

但是,S3 有一个专用的网站端点。这可以从您的 S3 存储桶 > 属性 > 静态网站托管访问。(您将在顶部看到链接)。

您应该使用此链接而不是 CloudFront 中出现的原始自动填充链接。您可以在创建发行版时将其放入,或者在创建后,您可以从“起源”和“起源组”选项卡进行编辑,然后使缓存无效。

这个链接看起来像: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 文档中提供了有关网站终端节点的更多信息。


kot*_*_14 5

这个线程对我来说真的很有帮助。我知道这已经很旧了,但是,我想添加一个aws-cdk最终对我有用的代码片段。我的用例需要我利用aws-cdk,因此,如果您期待aws-cdk基于解决方案,我将在此处添加它。

该代码片段index.html在 s3 和 cloudfront 中添加为错误页面。特别是对于 cloudfront,我添加了错误页面,并且/index.html响应为404403200


// 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);
Run Code Online (Sandbox Code Playgroud)

从这个帖子中真正帮助我的答案是:

/sf/answers/3965894061/

/sf/answers/4128484881/

/sf/answers/4494110771/


归档时间:

查看次数:

9149 次

最近记录:

6 年 前