CSR和SSR(更新中。。。)

前言

现在的web网站都是非常讲究用户体验,一般都会采用服务端渲染加客户端渲染一起实现功能。服务端渲染有利于搜索引擎优化(SEO),利于被网页爬虫抓取数据,多见于电商网站商品信息获取等。客户端渲染不利于搜索引擎优化,网页数据异步获取,首页加载时间长,用户体验相对较好,常用于不需要对SEO友好的地方

内容

1.服务端渲染(SSR)

简单理解就是浏览器发送请求后,服务器把客户端网页和数据在后台渲染解析,之后把渲染后的结果返回客户端。服务器端渲染的页面交互能力有限,如果要实现复杂交互,还是要通过引入 JavaScript 文件来辅助实现。

客户端拿到的是渲染后的结果,可以直接展示。服务器端渲染的页面在网络中传输的时候,传输的是一个真实的页面。因此,爬虫客户端当爬到我们的页面后,会分系我们给他提供的这个页面,此时,我们页面中的关键数据就会被爬虫给收录了。服务端渲染可以解决首页白屏时间过久,但是也容易导致服务器压力大,因此,可以使用服务器端的页面缓存技术,减轻服务器的渲染压力。

流程

让 React 代码在服务器端先执行一次,使得用户下载的 HTML 已经包含了所有的页面展示内容,这样,页面展示的过程只需要经历一个 HTTP 请求周期,TTFP 时间得到一倍以上的缩减。同时,由于 HTML 中已经包含了网页的所有内容,所以网页的 SEO 效果也会变的非常好。之后,我们让 React 代码在客户端再次执行,为 HTML 网页中的内容添加数据及事件的绑定,页面就具备了 React 的各种交互能力。
CSR和SSR(更新中。。。)_第1张图片

实现原理

上面我们说过,SSR 的工程中,React 代码会在客户端和服务器端各执行一次。你可能会想,这没什么问题,都是 JavaScript 代码,既可以在浏览器上运行,又可以在 Node 环境下运行。但事实并非如此,如果你的 React 代码里,存在直接操作 DOM 的代码,那么就无法实现 SSR 这种技术了,因为在 Node 环境下,是没有 DOM 这个概念存在的,所以这些代码在 Node 环境下是会报错的。

好在 React 框架中引入了一个概念叫做虚拟 DOM,虚拟 DOM 是真实 DOM 的一个 JavaScript 对象映射,React 在做页面操作时,实际上不是直接操作 DOM,而是操作虚拟 DOM,也就是操作普通的 JavaScript 对象,这就使得 SSR 成为了可能。在服务器,我可以操作 JavaScript 对象,判断环境是服务器环境,我们把虚拟 DOM 映射成字符串输出;在客户端,我也可以操作 JavaScript 对象,判断环境是客户端环境,我就直接将虚拟 DOM 映射成真实 DOM,完成页面挂载。

SSR框架图分析

CSR和SSR(更新中。。。)_第2张图片

可以看到,这里涉及两次路由:

服务器端路由:服务器端要根据请求的地址,判断要展示什么样的页面了。即在服务器端需要通过请求路径,找到路由组件

客户端路由(前端路由):当客户端接收到 JavaScript 文件后,要根据当前的路径,在浏览器上再判断当前要展示的组件,重新进行一次客户端渲染。即在客户端需通过浏览器中的网址,找到路由组件。

对于一个 React 应用来说,路由一般是整个程序的执行入口。在 SSR 中,服务器端的路由和客户端的路由不一样,也就意味着服务器端的入口代码和客户端的入口代码是不同的。

React 代码是要通过 Webpack 打包之后才能运行的,所以3,10步运行的代码,实际上是源代码打包过后生成的代码。所以,针对代码运行环境的不同,要进行有区别的 Webpack 打包。

服务器端路由 vs 客户端路由

实现 React 的 SSR 架构,我们需要让相同的 React 代码在客户端和服务器端各执行一次。大家注意,这里说的相同的 React 代码,指的是我们写的各种组件代码,所以在同构中,只有组件的代码是可以公用的,而路由这样的代码是没有办法公用的。

客户端路由:

// BrowserRouter 会自动从浏览器地址中,匹配对应的路由组件显示出来。

const App = () => {
  return (
    
      
        
) } ReactDom.render(, document.querySelector('#root'))

服务器端路由

const App = () => {
  return 
      
      
        
} Return ReactDom.renderToString()

服务器端路由代码相对要复杂一点,需要你把 location(当前请求路径)传递给 StaticRouter 组件,这样 StaticRouter 才能根据路径分析出当前所需要的组件是谁。(PS:StaticRouter 是 React-Router 针对服务器端渲染专门提供的一个路由组件。)

通过 BrowserRouter 我们能够匹配到浏览器即将显示的路由组件,对浏览器来说,我们需要把组件转化成 DOM,所以需要我们使用 ReactDom.render 方法来进行 DOM 的挂载。而 StaticRouter 能够在服务器端匹配到将要显示的组件,对服务器端来说,我们要把组件转化成字符串,这时我们只需要调用 ReactDom 提供的 renderToString 方法,就可以得到 App 组件对应的 HTML 字符串。

 

2. 客户端渲染(CSR)

在当今SPA框架,Vue,React,Angular大行天下的时候,前后端分离开发异常可见。客户端渲染简单理解就是浏览器发送页面请求(第一次请求),服务器返回的是一个模板页面,浏览器从上至下解析过程中需要发送ajax请求获取数据(第二次请求),最后再调用模板引擎(art-template等)渲染HTML结构,并把渲染后的结果添加到页面指定容器中,同时,JavaScript 代码会完成页面交互事件的绑定。

缺点:1.首先要加载 HTML 文件,之后要下载页面所需的 JavaScript 文件,然后 JavaScript 文件渲染生成页面。在这个渲染过程中至少涉及到两个 HTTP 请求周期。2.因为目前大多数搜索引擎主要识别的内容还是 HTML,对 JavaScript 文件内容的识别都还比较弱。CSR 项目的 SEO 能力极弱

客户端渲染因为数据是异步获取,所以在展示完整页面的过程中最少发起两次请求,数据是动态的添加到页面中,因此,非常不利于SEO,便于前后端分离开发。现如今前端采用Vue等框架开发非常多见,因此为了解决纯客户端渲染面临的问题,很多类似Vue中使用SSR和前后端同构的思想也非常常见。
CSR和SSR(更新中。。。)_第3张图片

具体流程图如下:

CSR和SSR(更新中。。。)_第4张图片

判断方式:查看网页源代码即可,如果是ssr方式,则可以直接看到数据。

3. 同构

现在我们知道浏览器显示页面:模板,内容(这俩可以认为是展示内容)和交互。显然SSR的交互还是需要js文件来执行

同构这个概念存在于 Vue,React 这些新型的前端框架中,同构实际上是客户端渲染和服务器端渲染的一个整合。我们把页面的展示内容和交互写在一起,让代码执行两次。在服务器端执行一次,用于实现服务器端渲染,在客户端再执行一次,用于接管页面交互。
CSR和SSR(更新中。。。)_第5张图片

待更新

服务器端代码和客户端代码的打包差异
SSR 中异步数据的获取 + Redux 的使用

参考

Webpack 官方网站
What is React Server Side Rendering and should I use it?
StaticRouter
The Pain and the Joy of creating isomorphic apps in ReactJS
React 中同构(SSR)原理脉络梳理

你可能感兴趣的