SSR 它到底香不香?细数 SSR 的利与弊

Wesley13
• 阅读 978

SSR 它到底香不香?细数 SSR 的利与弊

关注「前端向后」微信公众号,你将收获一系列「用心原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术

一.SSR 简介

SSR 它到底香不香?细数 SSR 的利与弊

SSR(Server-Side Rendering)并不是什么新奇的概念,前后端分层之前很长的一段时间里都是以服务端渲染为主(JSP、PHP),在服务端生成完整的 HTML 页面

摘自图解 SSR 等 6 种前端渲染模式

之所以要在服务端完成组件渲染工作,是因为有性能与可访问性两大优势

二.2 大优势

性能

与 CSR(Client-side rendering)模式相比,SSR 的性能优势体现在 2 方面:

  • 网络链路

  • 省去了客户端二次请求数据的网络传输开销

  • 服务端的网络环境要优于客户端,内部服务器之间通信路径也更短

  • 内容呈现

  • 首屏加载时间(FCP)更快

  • 浏览器内容解析优化机制能够发挥作用

网络链路上,由服务端发出接口请求,将返回数据随 HTML 响应内容一次性传递到客户端,比 CSR 二次请求更快。并且服务端网络传输速度更快(可以有更大带宽)、通信路径更短(可以同机房部署)、通信效率也更高(可以走 RPC)

内容呈现方面,CSR 的 HTML 大多是个空壳儿:

<!DOCTYPE html><html><head>    <title>My Awesome Web App</title>    <meta charset="utf-8"></head><body>    <div id="app"></div>    <script src="bundle.js"></script></body></html>

客户端拿到这种 HTML 只能立即渲染出一页空白,二次请求的数据回来之后才能呈现出有意义的内容,而 SSR 返回的 HTML 是有内容(数据)的,客户端能够立刻渲染出有意义的首屏内容(First Contentful Paint)。同时,静态的 HTML 文档让流式文档解析(streaming document parsing)等浏览器优化机制也能发挥其作用

关键区别是 SSR 不依赖客户端环境,包括网络环境和设备性能,即使用户的网络情况很糟(弱网)、设备性能很差(廉价、老旧设备),服务端渲染同样能够保障与最优用户环境(Wi-Fi 网络、高端设备)下相近的内容加载体验

可访问性

可访问性(accessibility)从两方面理解:

  • 对人:古老、特殊的用户设备,比如禁用了 JavaScript

  • 对机器人:爬虫程序等,典型的,搜索引擎爬虫

前者一般不必太过在意,后者要关注两大“客户”:

  • 搜索引擎:SEO

  • 社交媒体:抓取页面内容展示缩略信息(比如 Twitter 卡片等)

对 PC 站点而言,保证搜索引擎能够正确索引、准确理解页面内容,有重要的商业价值(搜索结果靠前,曝光量更大)。移动端虽不必考虑搜索引擎爬取,但也有类似的社交分享需求,社交媒体会抓取目标页面中的图片等作为缩略信息

P.S.诚然,有些搜索引擎能够正确爬取重 CSR 的 SPA,但不是全部,并且一大批社交媒体大都只从响应 HTML 中提取部分内容作为缩略信息,动态渲染 HTML(部分)内容的需求真切存在

虽具有这些优势,但 SSR 却远不如 CSR 应用广泛,是因为 SSR 面临着 6 大难题

三.6 个难题

难题 1:如何利用存量 CSR 代码实现同构

为了降级、复用、降低迁移成本等目的,通常会采用一套 JavaScript 代码跨客户端、服务端运行的同构方式来实现 SSR,然而,要让现有的 CSR 代码在服务端跑起来,先要解决诸多问题,例如:

  • 客户端依赖:分为 API 依赖和数据依赖两种,比如window/document之类的 JS API、设备相关数据信息(屏幕宽高、字体大小等)

  • 生命周期差异:例如 React 中,componentDidMount在服务端不执行

  • 异步操作不执行:服务端组件渲染过程是同步的,setTimeoutPromise之类的都等不了

  • 依赖库的适配:React、Redux、Dva 等等,甚至还有第三方库等不确定能否跑在 universal 环境,是否需要跨环境共享状态,以状态管理层为例,SSR 要求其 store 必须是可序列化的

  • 两边共享状态:每一份需要共享的状态都要考虑(服务端)如何传递、(客户端)如何接收

难题 2:服务的稳定性和性能要求

与客户端程序相比,服务端程序对稳定性和性能的要求严苛得多,例如:

  • 稳定性:异常崩溃、死循环

  • 性能:内存/CPU 资源占用、响应速度(网络传输距离等都要考虑在内)

因此面临后端专业性问题,Demo 级的 SSR 可能并不难,但高可用的 SSR 服务却绝非易事,如何应对大流量/高并发,如何识别故障,如何降级/快速恢复,哪些环节需要加缓存,缓存如何更新……

难题 3:配套设施的建设

SSR 最核心的部分是渲染服务,但除此之外还要考虑:

  • 本地开发套件(校验 + 构建 + 预览/HMR + 调试)

  • 发布流程(版本管理)

一整套的工程设施,在 SSR 模式下都需要重新考虑

难题 4:钱的问题

引入 SSR 渲染服务,实际上实在网络结构上加了一层节点,而大流量所过之处,每一层都是钱

Most importantly, SSR React apps cost a lot more in terms of resources since you need to keep a Node server up and running.

将组件渲染逻辑从客户端改到服务器执行,计算资源的成本必须考虑在内

难题 5:hydration 的性能损耗

客户端接到 SSR 响应之后,为了支持(基于 JavaScript 的)交互功能,仍然需要创建出组件树,与 SSR 渲染的 HTML 关联起来,并绑定相关的 DOM 事件,让页面变得可交互,这个过程称为 hydration

hydration 所需加载、执行的 JavaScript 代码不见得比 CSR 模式少多少,这部分工作在客户端执行,受限于用户设备的性能,在较差的设备下可能会造成可感知的不可交互时间:

  • CSR:可交互但是没有数据(还在异步请求数据,可能会持续很长)

  • SSR:有数据但是不可交互(拉到 JS 后开始 hydrate 的过程,能看到内容但是不可交互,一般不会持续很长)

富交互的场景下,后者不一定比前者用户体验更好

难题 6:数据请求

服务端同步渲染要求先发请求,拿到数据后才开始渲染组件,那么面临 3 个问题:

  • 数据依赖要从业务组件中剥离出来

  • 缺失客户端公参(包括 cookie 等客户端会默认带上的 header 信息)

  • 两边数据协议不同:服务端可能有更高效的通信方式,比如 RPC

目前主流的 CSR 模式下,数据依赖与业务组件存在紧耦合,要由服务端发起的数据请求全都掺杂在组件生命周期函数中,剥离数据依赖意味着需要同时改造 CSR 代码。公参、数据协议等差异对代码复用、可维护性也提出了一些新的挑战

四.应用场景

无论首屏加载性能还是可访问性,都是对内容密集型页面才有意义,而对于交互密集型的页面,SSR 所能提前渲染的内容不多,对用户意义不大,SEO 的必要性也值得商榷。因此,SSR 适用于偏静态的内容展示场景,典型的,商品详情、攻略、文章等图文混排的场景

另一方面,不一定非要 100% SSR,渲染特定页面,甚至只渲染个页面框架也是不错的应用:

“Application Shell” is an excellent concept. But sometimes, we might need to render a part of the page in the server. It could be the header with user info. In such cases, you need server-side rendering.

参考资料

  • A PAIN IN THE REACT: CHALLENGES BEHIND SSR

  • Why it’s tricky to measure Server-side Rendering performance:angular SSR 与 CSR 对照实测,数据可参考

  • Hey Next.js, Is Server Side Rendering Dead?

联系我      

如果心中仍有疑问,请查看原文并留下评论噢。(特别要紧的问题,可以直接微信联系 ayqywx )

本文分享自微信公众号 - 前端向后(backward-fe)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
SSR 与当年的 JSP、PHP 有什么区别?
!(https://oscimg.oschina.net/oscnet/3f3ea0100128439587eae97c2bcd2d33.jpg)关注「前端向后」微信公众号,你将收获一系列「用💖原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术写在前面SSR(ServerSid
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
FaaS 给前端带来了什么?
!(https://oscimg.oschina.net/oscnet/11e21dc76b205d94eeaa59b5a9e975034b5.jpg)关注「前端向后」微信公众号,你将收获一系列「用心原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术一.Serverless与FaaS
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这