传统的 web 开发中,URL 路由是由服务端程序(如 Express、Django 等)负责,根据用户请求的路径(如 /
, /about
)返回相应的 HTML 页面。
但由于 SPA(单页应用)的流行,React 及 Vue 的生态中都出现了在客户端做路由的组件,比如 React Router。
客户端路由即是,当 SPA 的页面变化时,新页面的内容由 JS 加载并渲染出来,同时 JS 代码会通过 History API 修改当面页面的 URL 地址。比如:
- 你在 https://example.com/ 上点击了 About 按钮,
- 页面并没有刷新,About 页面的内容通过 JS 渲染出来,浏览器地址变成了 https://example.com/about
如果你此时再刷新页面,浏览器会向服务器请求 https://example.com/about。由于 /about 页面是 JS 渲染的,服务端可能并没有这个页面,因此会返回 404 给前端。这种问题有几个解法。
用 hash (#) 来表示客户端路由
用 hash 来表达客户端路由的话,about 页的地址则变成 https://example.com/#about。这样服务端每次返回的都是 SPA 的初始 HTML ,客户端再根据 hash 做路由。
好处是 实现简单。缺点是 URL 很丑,并且页面都是 JS 渲染会 影响 SEO。
服务端对任意页面都返回 SPA 的初始 HTML
Express 有一个中间件是实现这种能力的,叫 express-history-api-fallback。
好处是不需要使用 hash 来做客户端路由。缺点有几个:
- 无法做纯前后端分离,即是前端页面没法完全托管在 CDN 上,仍然需要后端服务器输出 HTML
- 页面仍然是 JS 渲染,影响 SEO
服务端渲染(SSR,Server Side Rendering)
即是服务端先把整个页面,包括 JS 动态生成的内容,都生成一个完整的 HTML 提供给前端,但同时在这个 HTML 页面上也同样有 SPA 能力。这种方案借助于 Node.js 以及 headless webkit 等能力来运行 JS 及生成 HTML。优点是服务器直出完整内容,有利 SEO;缺点是实现复杂,并且更消耗服务端资源。
详情信息看 Web Frontend: Task: Server Side Rendering。
总结
如果页面的内容与 SEO 无关,比如是个工具类应用,那么可以用 hash 方式,简单直接。
如果内容与 SEO 有关,SSR 是首选。