手动刷新或写入时,React-router url 不起作用

IT技术 javascript reactjs url react-router
2021-02-02 20:05:16

我正在使用 React-router,当我点击链接按钮时它工作正常,但是当我刷新我的网页时它没有加载我想要的东西。

例如,我在localhost/joblist,一切都很好,因为我是按链接到达这里的。但是如果我刷新网页,我会得到:

Cannot GET /joblist

默认情况下,它不是这样工作的。起初,我有我的网址localhost/#/,并localhost/#/joblist和他们工作完全正常。但我不喜欢这种 URL,所以试图删除它#,我写道:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

这个问题不会发生在localhost/,这个总是返回我想要的。

编辑:此应用程序是单页的,因此/joblist不需要向任何服务器询问任何内容。

EDIT2:我的整个路由器。

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});
6个回答

查看对已接受答案的评论以及此问题的一般性质(“不起作用”),我认为这可能是对此处涉及的问题进行一些一般性解释的好地方。因此,此答案旨在作为 OP 特定用例的背景信息/详细说明。请多多包涵。

服务器端 vs 客户端

首先要了解的是,现在有 2 个地方可以解释 URL,而在“过去”中,过去只有 1 个地方。过去,生活简单的时候,一些用户向http://example.com/about服务器发送请求,服务器检查 URL 的路径部分,确定用户请求的是关于页面,然后返回该页面。

使用 React-Router 提供的客户端路由,事情就不那么简单了。首先,客户端还没有加载任何 JS 代码。因此,第一个请求将始终发送到服务器。然后将返回一个页面,其中包含加载 React 和 React Router 等所需的脚本标签。只有当这些脚本加载后,阶段 2 才会开始。在第 2 阶段,例如,当用户单击“关于我们”导航链接时,URL本地更改http://example.com/about(通过History API 实现),但不会向服务器发出请求. 相反,React Router 在客户端做它的事情,决定渲染哪个 React 视图,然后渲染它。假设您的关于页面不需要进行任何 REST 调用,它已经完成了。您已从主页转换到关于我们,而没有触发任何服务器请求。

所以基本上当你点击一个链接时,一些 Javascript 会运行来操作地址栏中的 URL,而不会导致页面刷新,这反过来会导致 React Router在客户端执行页面转换

但是现在考虑如果您将 URL 复制粘贴到地址栏中并将其通过电子邮件发送给朋友会发生什么。您的朋友尚未加载您的网站。也就是说,她还处于第一阶段她的机器上还没有运行 React Router。所以,她的浏览器将使服务器的请求http://example.com/about

这就是你的麻烦开始的地方。到目前为止,您只需在服务器的 webroot 中放置一个静态 HTML 即可。但是,当从服务器请求时404,所有其他 URL都会出错这些相同的 URL在客户端运行良好,因为 React Router 正在为你做路由,但它们在服务器端失败除非你让你的服务器理解它们。

结合服务器端和客户端路由

如果您希望http://example.com/aboutURL 在服务器端和客户端都工作,则需要在服务器端和客户端为其设置路由。有道理吗?

这就是您的选择开始的地方。解决方案的范围从完全绕过问题,通过返回引导 HTML 的包罗万象的路由,到服务器和客户端运行相同 JS 代码的完全同构方法。

.

完全绕过问题:哈希历史

使用Hash History而不是Browser History,关于页面的 URL 将如下所示: http://example.com/#/about 哈希 ( #) 符号后面的部分不会发送到服务器。所以服务器只能http://example.com/按预期看到和发送索引页面。React-Router 将拿起#/about零件并显示正确的页面。

缺点

  • “丑陋”的网址
  • 这种方法无法实现服务器端渲染。就搜索引擎优化 (SEO) 而言,您的网站由一个页面组成,上面几乎没有任何内容。

.

包罗万象

使用这种方法,您确实使用了浏览器历史记录,但只需在发送/*的服务器上设置一个包罗万象的功能index.html,有效地为您提供与哈希历史记录大致相同的情况。但是,您确实有干净的 URL,以后可以改进此方案,而不必使所有用户的收藏夹失效。

缺点

  • 设置更复杂
  • 仍然没有好的SEO

.

杂交种

在混合方法中,您可以通过为特定路由添加特定脚本来扩展包罗万象的场景。您可以编写一些简单的 PHP 脚本来返回包含内容的站点中最重要的页面,这样 Googlebot 至少可以看到您页面上的内容。

缺点

  • 设置更复杂
  • 对于您给予特殊待遇的那些路线,只有良好的 SEO
  • 复制用于在服务器和客户端上呈现内容的代码

.

同构

如果我们使用 Node JS 作为我们的服务器,这样我们就可以在两端运行相同的JS 代码呢?现在,我们在单个 react-router 配置中定义了所有路由,我们不需要复制渲染代码。可以这么说,这就是“圣杯”。如果页面转换发生在客户端,服务器会发送与我们最终得到的完全相同的标记。该解决方案在 SEO 方面是最佳的。

缺点

  • 服务器必须(能够)运行 JS。我已经尝试过 Java icw Nashorn,但它对我不起作用。实际上,这主要意味着您必须使用基于 Node JS 的服务器。
  • 许多棘手的环境问题(window在服务器端使用等)
  • 陡峭的学习曲线

.

我应该使用哪个?

选择一个你可以逃脱的。就我个人而言,我认为全能设置足够简单,所以这将是我的最低要求。此设置可让您随着时间的推移不断改进。如果你已经在使用 Node JS 作为你的服务器平台,我肯定会研究做一个同构应用程序。是的,一开始很难,但是一旦掌握了窍门,它实际上是解决问题的非常优雅的方法。

所以基本上,对我来说,这将是决定性因素。如果我的服务器在 Node JS 上运行,我会去同构;否则,我会选择 Catch-all 解决方案,并随着时间的推移和 SEO 要求的需要对其进行扩展(混合解决方案)。

如果您想了解有关 React 的同构(也称为“通用”)渲染的更多信息,有一些关于该主题的很好的教程:

此外,为了让您入门,我建议您查看一些入门套件。选择与您的技术堆栈选择相匹配的一个(请记住,React 只是 MVC 中的 V,您需要更多的东西来构建完整的应用程序)。首先看看 Facebook 自己发布的那个:

或者从社区中选择其中之一。现在有一个不错的站点,可以尝试为所有这些站点建立索引:

我从这些开始:

目前,我正在使用受上述两个入门套件启发的自制版本的通用渲染,但它们现在已经过时了。

祝你的任务好运!

伟大的职位 Stijn!您会建议为 Isomorphic react 应用程序使用入门套件吗?如果是这样,你能举一个你更喜欢的例子吗?
2021-03-19 20:05:16
@Paulos3000 有关一些相关问题,请参见此处:对于 Apache/php对于 Express/js对于 J2E/Java
2021-03-20 20:05:16
@LeonGaban 似乎自从写了这个答案,React Router 改变了他们的实现。他们现在为不同的历史拥有不同的路由器实例,并且他们在后台配置历史。基本原理仍然相同。
2021-03-25 20:05:16
@Paulos3000 这取决于您使用的服务器。基本上,您定义一个路由/*并使其响应您的 HTML 页面。这里的棘手之处在于确保您不会使用此路由拦截对 .js 和 .css 文件的请求。
2021-04-01 20:05:16
@Stijn de Witt 这是一个很好的澄清,并且在这个主题上得到了很好的回答。但是,当您的应用程序可以在子目录(例如通过 iis)中提供时,有哪些选项?即:域/应用程序名称/路由名称域/应用名称/子文件夹/路由名称
2021-04-06 20:05:16

这里的答案都非常有帮助,对我有用的是配置我的 Webpack 服务器以期待路由。

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

historyApiFallback 为我解决了这个问题。现在路由正常工作,我可以刷新页面或直接输入 URL。无需担心节点服务器上的变通方法。这个答案显然只在你使用 webpack 时才有效。

编辑:请在此处查看我的答案以了解为什么需要这样做的更详细原因:https : //stackoverflow.com/a/37622953/5217568

contentBase :':/' 因为您的应用程序文件可以从 url 访问
2021-03-20 20:05:16
对于通用开发目的,这是最好的解决方案。historyApiFallback足够了。至于所有其他选项,也可以从带有标志的 CLI 设置--history-api-fallback
2021-03-23 20:05:16
请注意,Webpack 团队建议不要在生产使用开发服务器。
2021-03-24 20:05:16
@Kunok 没有。这是开发的快速修复,但您仍然需要为生产找出一些方法。
2021-03-25 20:05:16
适用于 React 17。谢谢
2021-03-31 20:05:16

您可以更改.htaccess文件并插入:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]
</IfModule>

我正在使用react: "^16.12.0"andreact-router: "^5.1.2" 这种方法是万能的,可能是让您入门的最简单方法。

@TayyabFerozi 您必须确保RewriteBase最后一个之后的路径RewriteRule应用程序所在的文件夹匹配(如果它是子文件夹)
2021-03-17 20:05:16
这很好用!如果你不想重组你的应用程序,这是最简单的
2021-03-27 20:05:16
不要忘记 RewriteEngine On 作为第一行
2021-03-31 20:05:16
谁能帮我?这个 htaccess 放在哪里?添加文件后是否需要 npm run build ?
2021-04-03 20:05:16
请注意,此答案指的是 Apache 服务器上的配置。这不是 React 应用程序的一部分。
2021-04-07 20:05:16

对于React Router V4用户:

如果您尝试通过其他答案中提到的哈希历史技术解决此问题,请注意

<Router history={hashHistory} >

在 V4 中不起作用,请HashRouter改用:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

参考:HashRouter

您能否详细说明 HashRouter 解决此问题的原因?您提供的链接没有为我解释。另外,有没有办法隐藏路径中的哈希?我正在使用 BrowserRouter 但遇到了这个 404 问题。
2021-03-13 20:05:16
我正在使用浏览器路由器,它在刷新时导致 404 错误,但后来我用哈希路由器替换了浏览器路由器,但它无法正常工作。谢谢
2021-03-31 20:05:16

我刚刚使用 create-react-app 制作了一个网站,这里也遇到了同样的问题。BrowserRoutingreact-router-dom包中使用我在 Nginx 服务器上运行,为我解决的问题是将以下内容添加到/etc/nginx/yourconfig.conf

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

.htaccess如果您正在运行 Appache,这对应于将以下内容添加到

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

这似乎也是 Facebook 自己建议的解决方案,可以在这里找到

哇,这么简单的 nginx 解决方案;作为一个新的 nginx 用户,它就像一个魅力。只需复制粘贴即可。+1 用于链接到官方 fb 文档。一路走好。
2021-03-12 20:05:16
由于 Facebook 没有更改其相关文档,我只能假设程序是相同的。不过我有一段时间没试过了。
2021-03-14 20:05:16
作为记录:我正在使用带有 nginx 和 Angular 应用程序的 AWS 实例。这有效。
2021-03-26 20:05:16
“react”:“^16.8.6”,“react-router”:“^5.0.1”有什么不同需要吗?我尝试了这些解决方案(nginx 和 apache),但它们不起作用。
2021-03-26 20:05:16
你救我。我试图从昨天开始解决我的问题我厌倦了几个解决方案但我失败了。最后你帮我解决了这个路由器问题。啊非常感谢兄弟
2021-04-08 20:05:16