01
背景
让每一个用户获取到稳定、及时的页面体验,是前端工程师们一直以来努力的方向。
作为一个拥有丰富内容资源的视频网站,爱奇艺官网主站需要频繁进行节目上线或者下线、各种活动配置等操作调整,对于页面SSR服务的可用性及稳定性,都有着极高的要求。
在2019年之前,爱奇艺官网主站页面的SSR采用的是在CMS平台中书写Velocity模板,由Java编译,优点是渲染速度快,但缺点也非常明显:
(1)在CMS平台中开发体验不好:没有传统IDE方便,不能配置快捷键、不能安装插件等等,导致开发效率低下。
(2)前后端代码不同构:由于后端使用Velocity模板,而前端需要使用Vue,导致前后端代码不同构。
(3)破坏Vue组件封装性:由于Java无法编译Vue组件,所有的Vue组件都需要用Slot的方式在CMS平台中书写以达到SEO和SSR的目的。
基于以上所有原因,我们决定使用Node来进行SSR。因为我们的前端框架是Vue,因此我们选择了配套的Nuxt框架进行SSR。
使用Nuxt进行SSR,难点并不在于如何使用Nuxt,而在于如何维护这个服务,保证其性能、稳定性等,因此,本文将不会介绍Nuxt的使用,其语法可以参考官网,这里将主要从性能、缓存、限流、灾备、日志等几个方面来介绍我们是如何保证Nuxt服务的可用性及稳定性的。
02
Nuxt 稳定性提升之路
2.1 页面配置
首先介绍一个很重要的配置文件。在我们的项目根目录下,创建了一个页面配置文件,用来存放每个页面的通用配置,例如页面的缓存配置、Purge信息、主题色配置、广告信息配置等等,该文件导出一个Object, 键值为页面的Router Name,Value值为页面的配置信息:
// configs/pageinfo.js
export default {
'dianshiju-id': {...},
'zongyi': {
theme: 'dark', // 页面主题色配置
},
'home2020': {...},
'rank-hot': {...}
}
然后我们在Nuxt插件中根据请求的路由信息,读取对应的页面配置,并将其注入到所有的组件实例中,方便随时取用:
// plugins/pageinfo.js
import config from 'configs/pageinfo.js'
export default ({ route }, inject) => {
inject('pageInfo', config[route.name]) // 注入页面配置信息
}
因此你可以在组件的任何地方获取到页面配置信息而不需要通过Props一层层传递,页面通用配置也不会散落在项目各个地方,方便统一管理。
<div :class="$pageInfo.theme">我是综艺页面</div>
2.2 浏览器兼容性
虽然Nuxt理论上可以支持IE9,但IE9在很多方面都需要添加Polyfill,例如对History API的支持等,为了保持代码的简洁性,我们放弃了支持IE9-,但我们依然在框架中保留了一套机制来支持jQuery,使得高低版本可以共用HTML,而不需要单独为低版本写模板,从而最大程度的减少兼容低版本浏览器的成本。
大致思路为,Nuxt提供了一个’render.route’的钩子函数,该钩子函数的执行时机在生成HTML后,返回给用户之前。在这个钩子函数中,我们可以根据用户请求的UA信息判断用户版本,如果是低版本浏览器用户则移除HTML中高版本JS并注入低版本打包后的入口文件即可。
// nuxt.config.js
'render:route': (url, result, { req }) => {
if (isLowBrowser(req)) { // 根据用户ua信息判断是否是低版本
const $ = cheerio.load(result.html)
$('body script[src*=