服务器端 vs 客户端
首先要明白的是,现在有两个地方解释URL,而在“旧日子”里只有一个。过去,当生活还很简单时,某个用户向服务器发送了对 http://example.com/about
的请求,服务器检查了URL的路径部分,确定用户请求的是关于页面,然后将该页面返回。
使用客户端路由,这也是React Router提供的功能,事情变得不那么简单了。起初,客户端没有加载任何JavaScript代码。因此,第一个请求将始终发送到服务器。然后,服务器会返回包含所需脚本标记以加载React和React Router等内容的页面。只有在这些脚本加载完毕后才开始第二阶段。在第二阶段中,例如,当用户点击“关于我们”导航链接时,URL仅在本地更改为
http://example.com/about
(由
History API实现),但
不会向服务器发出任何请求。相反,React Router在客户端执行其操作,确定要呈现哪个React视图,并呈现它。假设您的关于页面不需要进行任何
REST调用,则已经完成。您已从
主页转换到
关于我们,而无需触发任何服务器请求。
基本上,当您单击链接时,会运行一些JavaScript来操作地址栏中的URL,而不会导致页面刷新,这反过来会使React Router在客户端执行页面转换。但是现在考虑一下,如果您复制并粘贴地址栏中的URL并将其发送给朋友会发生什么。您的朋友尚未加载您的网站。换句话说,她仍处于第一阶段。此时,她的计算机上没有运行React Router。因此,她的浏览器将向服务器发出请求
http://example.com/about
。
这就是问题所在。直到现在,您可以通过在服务器的Web根目录中放置静态HTML来摆脱这个问题。但是,对于所有其他URL,当从服务器请求时,它们会产生404错误。这些相同的URL在客户端上运行良好,因为React Router正在为您进行路由,但是除非您让服务器理解它们,否则它们在服务器端会失败。
结合服务器和客户端路由
如果你想让
http://example.com/about
的URL在服务器端和客户端都能使用,你需要在服务器端和客户端都设置路由。这很有道理,对吧?
然后你就需要做出选择了。解决方案从完全绕过问题(通过返回引导HTML的通用路由),到完全同构的方法(即服务器和客户端运行相同的JavaScript代码)不等。
绕过问题:哈希历史记录
使用
哈希历史记录,而不是
浏览器历史记录,关于页面的URL将看起来像这样:
http://example.com/#/about
在 URL 中,井号(
#
)符号后面的部分不会发送到服务器。因此服务器只看到
http://example.com/
并按预期发送索引页面。React Router 将获取
#/about
部分并显示正确的页面。
缺点:
- URL 不美观
- 无法使用这种方法进行服务器端渲染。就 搜索引擎优化(SEO)而言,您的网站只包含一个几乎没有任何内容的页面。
全捕获
使用这种方法,您确实使用了浏览器历史记录,但只需在服务器上设置全捕获,将 /*
发送到 index.html
,实际上给您提供了与哈希历史记录类似的情况。但是,您具有干净的 URL,并且稍后可以改进此方案,而无需使所有用户的收藏夹无效。
缺点:
混合
在混合方法中,您可以根据特定路由添加特定脚本,以扩展通用情况。您可以编写一些简单的PHP脚本来返回包含内容的站点最重要的页面,以便Googlebot至少可以看到页面上的内容。
缺点:
- 设置更加复杂
- 只有为特定路由提供特殊处理时,才能获得良好的SEO
- 在服务器和客户端上都需要重复渲染内容的代码
同构
如果我们使用
Node.js作为服务器,这样我们就可以在两端运行
相同的JavaScript代码了。现在,我们在单个react-router配置中定义了所有路由,并且不需要复制我们的渲染代码。这是所谓的“圣杯”。服务器发送的标记与如果页面转换发生在客户端上将得到的完全相同。从SEO方面来看,此解决方案是最佳的。
缺点:
- 服务器必须能够运行JavaScript。我已经尝试过使用Java和Nashorn一起使用,但对我来说不起作用。实际上,这主要意味着您必须使用基于Node.js的服务器。
- 许多棘手的环境问题(在服务器端使用
window
等)
- 陡峭的学习曲线
我应该选择哪一个?
选择您可以摆脱的那个。就我个人而言,我认为通用解决方案足够简单,因此这将是我的最低要求。这种设置允许您随着时间的推移改进事物。如果您已经将Node.js作为服务器平台,则应该调查执行同构应用程序。是的,一开始很难,但一旦掌握了它,它实际上是解决问题的非常优雅的解决方案。
因此,对我来说,这将是决定性因素。如果我的服务器运行在Node.js上,我会选择同构;否则,我会选择通用解决方案,并随着时间的推移(混合解决方案)扩展它以满足SEO要求。
如果您想了解React中的同构(也称为“通用”)渲染,有一些关于该主题的好教程:
此外,为了帮助您入门,我建议您查看一些入门套件。选择一个与您的技术堆栈匹配的套件(记住,React只是
MVC中的V,您需要更多的东西来构建完整的应用程序)。首先看看Facebook自己发布的那个。
或者选择社区中众多的项目之一。现在有一个很不错的网站,试图索引所有这些项目:
我曾经从这些项目开始:
目前,我正在使用一种自己创造的、受到上述两个起始包启发的通用渲染版本,但它们现在已经过时了。
祝你好运!
#
符号的?谢谢! - SudoPlzindex.html
即可。这将确保无论如何都会访问到index.html
。 - Trevor Hutto