反应路由器不工作在 aws s3桶

我将我的 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>
);
74217 次浏览

为什么会这样

您的问题是,您希望将责任传递给响应应用程序/javascript。该链接将工作,因为反应可以监听链接点击,并简单地更新浏览器 URL 栏中的路由。然而,如果你到了一个没有加载脚本(index.html 和 bundle.js 或者应用程序代码所在的位置)的地方,那么 JavaScript 就永远不会被加载,也没有机会处理请求。相反,无论您的服务器运行什么,都会处理这个请求,查看这个地方是否有资源,然后返回一个404错误或者它发现的其他错误。

解决办法

正如评论中提到的,这就是为什么你需要重定向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。请记住,它可能会影响服务器上的其他路由规则,所以这种配置是最简单的,如果您的反应应用程序有自己的位置,而不干扰其他东西。

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

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

将错误文档简单地指向 index.html

enter image description here

这对我有用。你可以处理反应路由器的错误页面。

2020年5月1日更新:

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

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

  1. 你可以把 Html放在 错误文档盒子里(就像 Alan Friedman 建议的那样)。
    • 转到 bucket (实际上有代码的那个,而不是你用来重定向的那个)-> 物业-> 静态网站托管:
    • 这不是“ hacky”,但它的工作方式,因为 react-router 工作: 它处理来自前端的请求,并将用户路由到 但总的来说,React 应用程序是单页的 申请。
    • 如果需要服务器端 React,可以考虑使用 下一个

enter image description here

  1. 您可以将指定的错误文件 错误放在 React 应用程序的 公众人士文件夹中,并在 静态网站托管: 错误文档框中放入: 错误。这个也可以。我已经测试过了。

  2. 使用 AWS CloudFront > CloudFront 分布 > The distribution of your bucket > 错误页面并添加所需的错误代码。如果您不使用 react-router(如下面的例子) ,bucket 将使用 错误403进行响应,这样您就可以使用 错误进行响应。

enter image description here

  1. 对于 TypeScript,目前 react-router不支持它,所以你应该考虑 选项2和选项3。他们将根据 这根线在未来的版本 6.*中更新这个库。

我遇到了这个问题,尽管我使用了已接受的答案中描述的配置,但是如果你仍然得到403个错误,而且你正在使用 AWS Cloudflare 管理器,你可以在发行版设置的“错误页面”选项卡中创建一个错误页面,使用以下配置:

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

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

这对我来说很有用,虽然我并不了解正确的服务器管理,但是希望有人能告诉我这是否是一个重大问题,如果是偶然的。

案例使用 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 bucket 中不存在的文件; bucket 中只有1个 html 文件,这是单页应用程序(Single Page Application)的 index.html,如本项目示例所示 将返回一个404响应,并且我们的自定义错误响应设置将劫持它。我们将返回一个200响应代码和 index.html 页面。 React 路由器将与 index.html 文件一起加载,它将查看 URL 并呈现正确的页面,而不是根路径。该页面将在 TTL 期间缓存对查询路径的所有请求。 为什么我们还要处理403?这是因为 Amazon S3为不存在的资产返回了这个响应代码,而不是404。例如,https://yourdomain.com/somewhere的 url 将查找一个不存在的名为某处(不带扩展名)的文件。

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

如果这个 S3桶是从 CloudFront 发行版提供的:

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

自定义错误页

enter image description here

根据以前的答案,解决问题的最佳方法是: 重新定义备用策略。 如果您想了解更多关于客户端路由和服务器端路由的信息,特别是 React JS 中的不同路由方法,请参阅 这篇文章

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

S3有两种端点,如果您遇到这个错误,您可能已经直接选择了 S3 bucket 作为 CloudFront 发行版的 Origin Domain Name 字段中的端点。

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

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

然而,S3有一个专用的网站端点。这是可以从你的 S3桶 > 属性 > 静态网站托管。(你会看到顶部的链接)。

您应该使用这个链接,而不是 CloudFront 中出现的原始自动填充链接。您可以在创建发行版时将其放入,或者在创建之后,可以从选项卡 Origins and Origins Group 进行编辑,然后使缓存失效。

这个链接看起来像: bucket-name.s3-website.region-name.amazonaws.com

一旦这种情况传播和改变,就应该修复您的问题。

Dr: 不要在 CloudFront 中使用默认的 S3端点。改为使用 S3网站端点。您的原始域应该是这样的: my-application.s3-website.us-east-1.amazonaws.com而不是像 my-application.s3.amazonaws.com

关于网站端点的更多信息可以在 AWS 文档 给你中找到。

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

使用静态托管更新 s3的配置,使用 index.html 更新默认配置 在此输入图像描述

添加带有错误页面的 CloudFront

404 error-> index.html->status 200

在此输入图像描述

我用 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进行任何更改。

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

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

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

这个帖子对我很有帮助。我知道这是老的,但是,我想添加一个 aws-cdk代码片段,最终为我工作。我的用例需要我利用 aws-cdk,所以,我在这里添加它,如果你期待一个基于 aws-cdk的解决方案。

代码片段将 index.html作为错误页面添加到 s3和 Cloudfront 中。对于 Cloudfront,我为 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

下面的配置已解决 enter image description here

更新相关云端分布的错误页面,并自定义错误响应,从 HTTP状态码404-not-found 到代码200-ok,响应页面路径为/和接近于零的生存时间

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

你可以在这里了解更多关于 CloudFront 函数的信息: Https://docs.aws.amazon.com/amazoncloudfront/latest/developerguide/cloudfront-functions.html

主要思想是使用 CloudFront 函数为任何不针对静态文件的请求重写请求 Uri,即。JS.CSS.Html 等等。.并使其指向/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

100% 的工作和测试主机 SPA 网站像反应在 S3桶 并修复404子页面问题

  1. 登录亚马逊控制台
  2. 搜索 云层
  3. 选择你的 分配
  4. 选择 错误页面选项卡并单击 < strong > Create customError Response enter image description here
  5. 在这里创建一个响应规则 enter image description here
  6. 保存错误规则

你已经完成了!

这里有很多答案,所以我想对现有的方法做一个调查,比较各种方法的优缺点。

上前 描述 优点 缺点 答案
CloudFront 函数 使用 AWS CloudFront 函数将请求写入 SPA 的根文档,例如 index.html 没有抛出错误,没有重定向,显然有利于搜索引擎优化。 额外的费用(尽管在编写本文时,免费层允许每月免费调用200万次,此后每百万次调用只有10美分)。要部署/管理的额外基础设施。 KG
主机作为网站 将 S3 bucket 配置为承载一个网站,而不是一个 REST API。 当 S3以这种方式配置时,它会自动处理路由。 不能使用 OrignAccessIdentity 。相反,S3端点是通过 HTTP 公开的,您需要限制访问 使用自定义标头,这比较复杂。 FV
错误重定向(404和403) 绝大多数的答案似乎提供了一些这方面的味道。其思想是允许发生404或403错误,但是然后返回 index.html(或不管 SPA 根文档是什么)作为错误页面。 很容易实现。 每次尝试访问非根 URL 时都会导致客户端重定向。显然这对搜索引擎优化不利。 AR V名爵花生酱K,< a href = “ https://stackoverflow. com/a/71591815/5134722”> KS
URL 散列/散列 有些解决方案涉及使用 URL 中的散列来路由子页面。 没有重定向和额外的 AWS 资源没有成本。 这些方法似乎存在一些问题——参见 给你。一些人认为 URL 中的散列很难看; 似乎确实有方法可以减轻这种情况,但是这涉及到一些额外的复杂性。 AA ,< a href = “ https://stackoverflow. com/a/64442122/5134722”> B

注意: 这个答案是根据我在其他答案中读到的内容得出的。除了“ CloudFront 函数”方法之外,我还没有完全测试过其他任何方法,我可以确认这种方法是可行的。

我将添加另一个方法,因为 CloudFront 函数选项非常棒,只是它返回 soft-404s,即 不利于你的搜索引擎优化

此方法使用 CloudFront 函数和 CloudFront 分布自定义错误页来返回包含200个状态代码的有效 URI 和包含404个状态代码的无效 URI。

功能:

这个特殊的功能是为 反应路由器 v6快速启动指南中指定的路由配置设计的,其中 /invoices/expenses嵌套在根路由 /之下,再加上404s *的全部路由。它将请求重定向到 validPaths数组中包含的 URI 到 /index.html,允许其他请求按原样通过。您应该调整此函数以反映 SPA 的有效 URI,并且您可以选择更改此函数如何根据 validPaths检查 request.uri

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


var validPaths = ['/','/invoices','/expenses'];


if( validPaths.includes(request.uri) ){
request.uri = "/index.html"
}
     

return request;
}

任何有效的静态资产请求仍将返回静态资产,但对页面或资产的无效请求将返回 XML 中带有403状态码的错误。

错误处理程序:

如果我们结合自定义的错误响应,将403s 转换成404s +/index.html,我们有一个应用程序,将允许反应路由器正常工作,而不返回软404s!您的本地搜索引擎爬虫将很高兴。

CloudFront 分发自定义错误响应表单图像链接,因为我没有足够的点显示在内联。

其他想法:

这种方法的缺点是必须手动维护函数中有效 URI 的列表。在 这篇文章中还讨论了其他类似的方法。

注意,对于这种方法,您应该使用 RESTAPI 作为您的端点,其访问受到 OAI 的限制,而不是 S3静态网站端点。这将确保所有到您的网站的流量是通过您的 CloudFront 发行版,保护私人内容(如果适用) ,但也确保您的 CloudFront 日志,如果您使用它们,是完整的。

在最新版本中,Route被认为是 Routes的子代,所以我们应该将 Route包装在 Routes中。

<Routes>
<Route path="/home" element={<Home/>}
</Routes>