停止使用客户端的路由重定向

263 阅读5分钟

首先,让我们确保我们谈论的是同一件事:

function App() {
  return (
    <BrowserRouter>
      <Redirect from="/old-route" to="/new-route" />
      {/* ... more routes etc... */}
    </BrowserRouter>
  )
}

(或者你在自己的框架中如何完成同样的事情)。

不是在谈论这种用法(从文档中借用的例子):

<Route exact path="/">
  {loggedIn ? <Redirect to="/dashboard" /> : <PublicHomePage />}
</Route>

这在技术上是没有问题的,尽管在你的应用程序中可能有更好的方法来处理这个问题。请阅读我的文章《React应用程序中的认证》以了解更多相关信息。

好了,现在我们已经清楚了,让我解释一下为什么,然后你应该做什么来代替。

首先,使用客户端重定向(如Redirect的fromprop或类似的)的目的是确保用户不会登陆到一个你期望他们能登陆的URL,而是将他们重定向到一个不同的URL。这方面的一个很好的例子是,当你改变你的应用程序的URL方案。或者是你给你的用户发送了一封带有错误URL的电子邮件,现在你被困在了用户的重定向上,直到永远。

不管是什么情况...如果你知道你想重定向用户URL,那么你最好在服务器上重定向他们。让我们来谈谈为什么客户端的重定向会有这样的问题。

149.3 千字节的重定向 😱

假设一个用户来到你的应用程序,并点击了/old-route 。在浏览器知道它在一条错误的路线上之前,他们必须下载你的应用程序。不管你的代码分割能力有多强,他们至少需要react,react-dom, 和react-router-dom 。那是一些字节!

  • react@16.13.1 - 6.3kB
  • react-dom@16.13.1 - 114.6kB
  • react-router-dom@5.1.2 - 28.4kB

这些大小都是经过压缩的,但未经压缩,因为压缩取决于太多的变量,无法进行准确的比较。另外,我意识到React Router v6很快就会到来,并会大大减少捆绑的大小,但请听我说!这还不包括你的应用程序。

而且这还不包括你自己的代码!

现在,让我们不要虚情假意!<Redirect /> ,只支持在同一个应用程序内重定向,所以用户无论如何都需要下载所有这些东西。但这个概念仍然适用。不要做客户端重定向,从一个已知路由到另一个已知路由。如果是从一个应用程序到另一个,那么用户只是下载并运行了一堆他们不需要的代码。另外,即使是在应用内,那么根据你对代码分割的配置情况,这绝对有可能导致用户下载过多或引发瀑布效应(导致次优性能)。

至于你自己的应用程序中使用<Redirect /> ,用户将不得不等待,直到应用程序完成加载并实际运行后,他们地址栏中的URL才会更新为正确的URL。<Redirect /> 也许这本身并不足以成为避免使用from 的理由,但请继续阅读。

HTTP状态代码

这绝对是一个足以避免客户端重定向的理由(比如<Redirect />from )。当用户通过JavaScript重定向时,没有办法通知浏览器(或搜索引擎)他们之前所在的URL不再正确,而新的才是正确的。这对搜索引擎浏览器的缓存有影响(对错误状态代码的缓存处理也很有意思)。

服务器端重定向

我将向你展示我为bookshelf.lol实现的三个服务器端重定向。在bookhelf应用中,我在/ 的主页路线上没有任何东西(注意,bookhelf应用纯粹是为了教育目的,所以像这样半刻意的决定是不容质疑的。请注意,谢谢你)。

因此,每个对/ 的请求都应该被重定向到/list 。我想用302 来重定向,因为很可能在未来的某个时间点,我会改变主意,我不想处理破坏浏览器或搜索引擎对这个特定重定向的缓存。

Netlify (生产)

使用Netlify,你可以在 netlify.toml 文件中配置重定向,但我选择了_redirects 文件的选项。下面是该文件需要的内容,以使该重定向到位:

/  /list  302!

你可以在这里查看这个文件现在的样子。

如果我想使用netlify.toml 文件,那么它将更像这样:

[[redirects]]
  from = "/"
  to = "/list"
  status = 302
  force = true

本地建立的文件

一旦我建立了书架应用程序,如果我想在本地运行它,我就用serve来实现。这个CLI使用serve-handler它可以像这样用serve.json 来配置。

{
  "redirects": [
    {
      "source": "/",
      "destination": "/list",
      "type": 302
    }
  ]
}

你可以在这里查看这个文件的现状。

本地开发中的文件

书架应用程序是用Create React App构建的(它使用react-scripts )。这意味着开发服务器完全由我在幕后处理。幸运的是,react-scripts 确实允许为代理目的定制服务器,我可以通过在src/setupProxy.js 创建一个文件来使用它进行重定向。这只是导出了一个接受Express应用程序的函数,然后我就可以在要求使用res.redirect当请求/路线时,我可以使用

function proxy(app) {
  app.get(/^\/$/, (req, res) => res.redirect('/list'))
}

module.exports = proxy

你可以在这里查看这个文件,就像现在这样。

结论

无论你最终将你的应用程序发布到什么主机上,可能都有一些配置重定向的方法(如果没有,那就太奇怪了)。为了避免简单的重定向,可能会感觉到很多工作:

<Redirect from="/" to="/list" />

但实际上,成本是相当小的(设置一次就忘了),而且在语义上正确的好处超过了这些成本。

一般来说,遵循网络的语义对现有的工具更好(就像使用语义标记对无障碍性更好一样)。如果网络标准满足用例,那么就使用网络标准。

感谢Ryan Florence(React Router的创造者),他让我相信了这个想法。