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

新手上路,请多包涵

我正在使用 React-router,当我单击链接按钮时它工作正常,但是当我刷新我的网页时它不会加载我想要的内容。

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

Cannot GET /joblist

默认情况下,它不是这样工作的。最初,我的 URL 为 localhost/#/localhost/#/joblist ,它们工作得非常好。但我不喜欢这种 URL,所以试图删除那个 # ,我写道:

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

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

这个应用程序是单页的,所以 /joblist 不需要向任何服务器询问任何内容。

我的整个路由器。

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);
});

原文由 DavidDev 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 768
2 个回答

服务器端与客户端

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

使用 React Router 提供的客户端路由,事情就不那么简单了。起初,客户端还没有加载任何 JavaScript 代码。所以第一个请求将永远是服务器。然后,这将返回一个页面,其中包含加载 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 即可。但是, _当从服务器请求时_,这会给所有其他 URL 带来 404 错误。这些相同的 URL 在客户端 工作正常,因为 React Router 正在为你做路由,但它们 在服务器端 失败,除非你让你的服务器理解它们。

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

如果您希望 http://example.com/about URL 在服务器端和客户端都工作,您需要在服务器端和客户端为其设置路由。这是有道理的,对吧?

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

完全绕过问题:哈希历史

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

缺点

  • 服务器 _必须(能够)运行 JavaScript。我已经尝试将 Java 与 [Nashorn](https://en.wikipedia.org/wiki/Nashorn(JavaScript_engine)) 结合使用,但它对我不起作用。实际上,这主要意味着您必须使用基于 Node.js 的服务器。

  • 许多棘手的环境问题(在服务器端使用 window 等)

  • 陡峭的学习曲线

我应该使用哪个?

选择一个你可以逃脱的。就个人而言,我认为包罗万象很容易设置,所以这将是我的最低要求。此设置允许您随着时间的推移改进事物。如果你已经在使用 Node.js 作为你的服务器平台,我肯定会研究做一个同构应用程序。是的,一开始很难,但一旦你掌握了窍门,它实际上是解决问题的一个非常优雅的解决方案。

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

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

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

或者从社区中选择一个。现在有一个不错的网站试图索引所有这些:

我从这些开始:

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

祝你的任务好运!

原文由 Stijn de Witt 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您使用 Apache 作为 Web 服务器,您可以将其插入到您的 .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"react-router: "^5.1.2" 这种方法是万能的,可能是最简单的入门方法。

原文由 BrahimS 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题