引言
今天我们来聊一下首屏优化之SSR-服务端渲染(Server-Side Rendering)。
可能很多朋友并不了解什么是 SSR,包括在工作中写的网站是什么类型的也不太清楚,是 CSR 还是 SSR?作者在阅读过大量的文章之后,今天也来分享一下自己的理解,这部分内容确实不太好理解,我们更多的以例子来理解为主,Let‘s go!
CSR
在聊 ssr 之前,我们先来聊一下CSR,即客户端渲染(Client-Side Rendering,是一种在客户端(即浏览器)完成网页内容生成和渲染的技术,也就是浏览器端完成渲染。这个过程需要等待浏览器加载、解析和执行 JS 代码才能生成页面内容,首屏可能会有延迟。
如果大家在工作中是做后台管理相关的,那大概率就是 CSR。
一般情况下,CSR 项目都可以直接通过 vue 或者 react 脚手架进行创建,这里我们使用 react 创建一个 csr 应用,vue 也是一样的道理,然后运行后去网络中看一下文件加载的内容。
打开网络 -- 打开第一个网络地址 -- 点击查看响应内容
可以看到,在响应中,我们只看到了一个空的 div,如果你的网站也是这样,那就是 CSR 渲染的方式了。
为了更好的让 vue 用户理解,我们也打开一个 vue 的网站看一下,可以看到是一样的,都是一个div 空标签。
在 CSR 渲染中,为什么说不利于首屏优化呢?在上面的那张截图中我们看到,script 的加载方式是 defer,也就是说 script 脚本和 html 是同时加载的,这个可以在我之前的那篇关于 script 的加载方式中了解到,所以在解析到 script 脚本时并不会立即执行,而是在 html 加载完毕之后,再执行脚本内容,那也有可能先加载好 html,script 需要等待一会再解析完毕,这可能会导致白屏现象,而在 react 中我们可以使用 lazy 和 Suspense 来实现一下,这两个的功能就是当页面还没有加载完毕时,会显示 loading 的内容,来看一下。
我们把网速调整为快速 3G 看一下。
来看一下页面的加载情况,很明显,当网速慢时,页面存在一两秒的 loanig 加载状态
也就是说,我们的页面初始渲染时只有一个空的div,剩余的内容需要等待js加载完毕渲染到页面中。
那如果直接使用 ssr 渲染呢,同样的慢速3G,来看一下。
可以看到,当点击刷新之后,页面会先显示我通过 ssr 渲染的内容,而不会存在空白页面的情况,不需要等待js加载结束,因为页面所需要显示的html内容已经通过服务端提前渲染好了,浏览器拿到的就是可以直接显示的内容,这样是不是可以优化首屏加载体验呢?
SSR
前面我们说了 CSR,我们对 CSR 有了基本的了解之后,对 ssr 理解起来也会更容易一些。
什么是SSR?
SSR,即服务端渲染,是指在服务器端生成 HTML 内容并将其发送到客户端。这样一来,用户在首次访问页面时,浏览器可以直接展示完整的HTML内容,而无需等待 JS 在客户端完成渲染。
还是跟上面的一样,我们来看一下网站的响应的内容,这里我们拿掘金进行举例。
很明显,我们看到,掘金并不是和上面的 CSR 网站一样,直接返回一个空的 div,而是返回了很多的 html 内容,掘金的这个网站是采用 nuxt 实现的 ssr 渲染,nuxt 是基于 vue 实现的 ssr 框架,而react 对应的 next。
那掘金的div内的内容都是什么呢?
往下看,我们发现是首页一些 nav,以及侧边栏的信息,这些直接通过ssr服务端进行渲染出来的
同样的,我们也是刷新一下掘金网站再次验证一下,可以看到刷新网站并且3G情况下,掘金也不会出现白屏现象,nav 和侧边栏都是有数据的,而中间的内容是动态获取的,也就是说掘金的首页采取的是 SSR+CSR 混合模式,静态展示的内容采用 SSR,动态获取的内容采用CSR。
而静态展示的内容也是从服务端获取的,因为是不经常变化的,所以加了缓存浏览器的缓存策略,在一段时间内没有过期的话直接从本地获取,第一次会从服务端获取,后端则会直接从缓存中获取,可以通过Ttag字段看到。
在请求时携带上次服务端返回的etag,服务端经过比对如果没有静态资源没有发生变化,则不会重复请求,直接进行服用即可,可以看我之前的那篇强缓存和协商缓存的文章,里面有讲到这个。
这里我们也简单实现一下SSR+CSR渲染的模式,因为在我们实际开发中,首页很多情况下是需要动态获取数据的,不太可能只采取一种模式。
SSR举例
这里我们直接使用框架 Next.js 实现服务端渲染 ssr,vue 可以直接使用Nuxt.js。
Header 组件是 ssr 渲染,负责一些头部的内容显示,Header组件是一些静态的内容,并没有动态生成的内容。
ArticleList组件是 csr 渲染,负责一些动态数据请求
Header组件---SSR
ArticleList组件--CSR
运行一下页面试试,可以看到,浏览器会直接显示我们的 Header 组件的内容,在等待一会之后会显示动态加载的内容。
再来看一下浏览器响应的情况,在浏览器的响应内容中,看到 div 中的内容时我们的Header的内容,而 ArticleList 组件动态获取的内容是没有的。
通过上面的举例,相信大家对 ssr 已经有一些理解了。
基本就是在 ssr 渲染中,服务器端生成 HTML 内容,然后将其发送到客户端浏览器。用户在收到 HTML 时,已经包含了渲染后的页面内容,而不是一个空的div,这样则可以直接显示到浏览器上面,而不需要等到js加载结束再显示出来。
然而在 csr 渲染中,浏览器接收到的却是一个空的div,剩余的内容需要在js加载结束后,展示给用户。
这就是不同。
SSR-动态渲染
当然在 ssr 服务端渲染时,也可以请求服务端的数据,只不过针对不经常变化的资源,我么可以采取缓存策略,这个也需要后端配合,这样设置之后就只需要第一次向服务器发起请求,后续如果资源没有发生变化则会直接用我们之前的数据。
就类似于掘金的文章详情页面,如果能直接把文章内容通过服务端进行渲染,那就会有更好的SEO优化,在百度等搜索引擎搜索时,也会有更好的排名。
比如在我们的 Header 组件中,是使用的 SSR 渲染,因为需要更好的 SEO 优化,我们把模拟的文章内容通过服务端进行请求,然后渲染到页面中,这个内容也会直接返回给浏览器,实在服务端已经处理好的内容。
我们看一下浏览器的接口请求情况,可以看到除了我们写死的静态内容,也有从服务端请求的数据,但是这个内容都直接通过html返回给了浏览器,那对于SEO优化有很大的好处。
但是同样通过服务端获取请求,不也是需要加载时间吗?是的,但是我们只需要第一次加载一次,后续可以把内容缓存下来,通过后端的配置决定什么时候重新请求资源即可。
看一下掘金的文章页面,是把所有的文章内容直接通过 ssr 的方式返回给浏览器的。
如何实现SSR?
可以直接使用现有的框架实现,比如Next(react),Nuxt(vue)
总结
SSR的特点
- 首屏加载速度快,用户可以立即看到内容。
- 有利于SEO,搜索引擎可以直接抓取到完整内容。
- 对服务器要求较高,需要在服务端完成渲染工作。
- 页面交互可能需要等待JS加载完成。
CSR的特点
- 初次加载可能较慢,因为需要等待JS代码执行。
- 后续页面切换通常很快,因为只需更新变化的部分。
- 对服务器压力较小,大部分渲染工作在客户端完成。
- SEO表现可能较差,因为初始HTML内容很少。
选择 SSR 还是 CSR 要根据项目的具体需求来决定。对于要求快速首屏加载和 SEO 友好的项目,SSR 可能更为合适;对于更注重交互性能的单页应用,CSR 可能更能满足需求。