反应服务器端渲染与客户端路由

react server side rendering with client side routing

我的主页路由 ( / ) 的初始服务器渲染工作正常。

此外,随后的客户端导航到 ( /#/page2 ) 工作正常。

但是,如果我直接从地址栏加载/#/page2,服务器呈现的主页首先在浏览器中加载,然后明显过渡到/#/page2,这不是我想要的。我只想显示/#/page2,而不先刷新主页。

发生的事情是节点正在为对 / 的请求提供主页,然后当响应到达客户端时,客户端是 运行 /#/page2 的路由处理程序。两者都表现正确。但这不是我想要的。

如何避免这种行为?

我认为我需要的是一种让服务器和客户端都知道不同路由并且都能够处理它们(同构)的方法,但是,url 的片段部分服务器不知道。

还有其他人有这个问题吗?

这个问题不是 React 特有的。具体到SSR去深link.

我的节点路由器处理“/”如下

router.get('/', function(req, res) {
  var React = require('react');
  var Router = require('react-router');
  var Routes = require("../app/clapi-routes.jsx");

  var router = Router.create({location: req.url, routes: Routes});
  router.run(function(Handler, state) {
    var html = React.renderToString(<Handler/>);
    return res.render('index.ejs', {html:html});
  })
});

index.ejs 就是:

<html lang="en">
  <head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="/css/json-inspector.css"/>
  </head>
<body style="margin:0">
  <%- html %>
  <script src="/build/bundle.js"></script>
</body>
</html>

停止使用哈希驱动的导航。 # 之后的所有内容仅供客户端使用,对于此类内容毫无用处。所以 /#/page2 需要变成 /page2.

我不确定 React,但其他路由系统也存在同样的问题,关闭 urls 中的 # 真的很容易。

在angular的ui-router中是这样完成的$locationProvider.html5Mode(true);

您的服务器端需要知道对您的客户端知道的所有 URL 做出反应,但这就是实现稳健性的方式 - 无论导航如何发生(客户端事件或 link点击),客户端和服务端都可以端到端的处理场景。

我发现有两个步骤:

首先: 将 React 路由器更改为使用 Router.HistoryLocation 而不是默认值 (HashLocation)。这使您的路由使用 html5 推送状态并将您的路由路径从 /#/page2 更改为 /page2

// in app.jsx (client side routing)

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

其次:确保您的节点页面路由所有return相同"index.ejs"。否则你的路线,比如 /page2 将在整页刷新(或深度链接)时 404

// in server.js (server side routing)

router.get('*', function(req, res) {
  Router.run(Routes, req.path, function(Handler) {
    var html = React.renderToString(<Handler/>);
    return res.render('index.ejs', {html: html});
  });
});

另外:如果你正在服务"public"静态资产,在你的路线之前声明,并删除任何public/index.html 你可能有这样你的节点路由器处理 / 请求与服务器呈现的内容。