服务端渲染

目录

  • 基本概念
  • 发展背景
  • 对比
    • 服务器端渲染的优缺点是?
      • 优点
      • 缺点
    • 客户端渲染的优缺点是?
      • 优点
      • 缺点
  • 使用服务端渲染
    • JSP(JavaServer Pages)
    • express + ejs
    • express + react
    • vue + nuxt
  • 怎样选择?
    • 适用于客户端渲染的项目:
    • 适用于服务端渲染的项目:
    • 综合方案?

基本概念

  • SSR (server side render)服务端渲染,是指由服务侧(server side)完成页面的DOM结构拼接,然后发送到浏览器,为其绑定状态与事件,成为完全可交互页面的过程。
  • CSR(client side render)客户端渲染,是指由客户端(client side)JS完成页面和数据的拼接,生成DOM结构再交由浏览器渲染成页面的过程。
  • SPA(single page application)单页面应用,指只有一张WEB页面的应用,也就是说在导航切换的过程中页面不会刷新,只是局部更新内容。SPA实现的原理就采用了CSR,页面中所有内容由JS控制,需要浏览器进行JS解析才能显示出来。
  • SEO(search engine optimization)搜索引擎优化,利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。
  • SSG(static side generate),无需服务器实时动态编译,在构建时针对特定路由简单的生成静态HTML文件,我们也可称之为预渲染。
  • AJAX(Asynchronous Javascript And XML)异步JS&XML,前台发送AJAX请求后并不会阻塞其他操作,数据接手后再异步更新页面,也就是说可以在不重新加载整个网页的情况下,对网页的局部数据进行更新。

发展背景

  • 早些年的互联网时代,应用逻辑相对比较简单,与用户的交互并不是很多,所以大部分的网站都是由前端工程师开发好HTML页面,后台拿到页面后转成后台模板语法,将动态的数据添加进去,如JSP、Velocity等。后台开发完成后启动服务,当我们访问页面时,后台定位到请求的路径,按照页面需求从数据库抓取数据,随之进行HTML文件的拼接,最后返回给浏览器。这也就是初级的服务端渲染

  • 随着应用复杂性提高,用户对于界面的要求越来越高,前端交互也越发显得重要。同时,AJAX的兴起把传统的开发模式带入到一个新时代:前后端分离式开发,即前端有自己的服务,不依赖于后台,前后端通过AJAX进行数据交互。前端发送请求,通过后台提供的api获取数据,然后通过前端js进行HTML页面的生成,展示给浏览器。这也就是所谓的客户端渲染
    在这里插入图片描述

  • SPA单页面应用就是这个时代的产物,一些框架也由此盛行,如Vue、React、Angular等,配合着webpack、gulp等打包工具,实现了前端开发环境热更新部署,生产环境的压缩优化打包,让前端开发效率及质量大大提高。

  • SPA单页面应用虽好,但同时也伴随着一些弊端的产生:

    1. 对SEO(搜索引擎优化)不友好,因为他们的源码长这样:
      在这里插入图片描述
      SEO是通过抓取我们网页源码中的关键字来建立索引库的,所以这种源码中没有内容,而是通过js添加进去的网站就会被搜索引擎直接pass掉了。
    2. 首屏加载速度慢,因为页面内容是由js拼接出来的,所以浏览器会等待js处理完成后才能渲染真正的DOM结构,多了一些等待时间。
  • 为了解决SEO和首屏加载慢的问题,前端攻城狮们在浏览器与后台服务间搭建一个服务器(一般是用node.js搭建的),专门用于服务端渲染。其流程是这样的:
    在这里插入图片描述

对比

服务器端渲染的优缺点是?

优点

  • 前端耗时少。因为后端拼接完了html,浏览器只需要直接渲染出来。
  • 有利于SEO。因为在后端有完整的html页面,所以爬虫更容易爬取获得信息,更有利于seo。
  • 无需占用客户端资源。即解析模板的工作完全交由后端来做,客户端只要解析标准的html页面即可,这样对于客户端的资源占用更少,尤其是移动端,也可以更省电。
  • 后端生成静态化文件。即生成缓存片段,这样就可以减少数据库查询浪费的时间了,且对于数据变化不大的页面非常高效 。

缺点

  • 不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,则对于前端复杂度高的项目,不利于项目高效开发。另外,如果是服务器端渲染,则前端一般就是写一个静态html文件,然后后端再修改为模板,这样是非常低效的,并且还常常需要前后端共同完成修改的动作; 或者是前端直接完成html模板,然后交由后端。另外,如果后端改了模板,前端还需要根据改动的模板再调节css,这样使得前后端联调的时间增加。
  • 占用服务器端资源。即服务器端完成html模板的解析,如果请求较多,会对服务器造成一定的访问压力。而如果使用前端渲染,就是把这些解析的压力分摊了前端,而这里确实完全交给了一个服务器。

客户端渲染的优缺点是?

优点

  • 前后端分离。前端专注于前端UI,后端专注于api开发,且前端有更多的选择性,而不需要遵循后端特定的模板。
  • 体验更好。比如,我们将网站做成SPA或者部分内容做成SPA,这样,尤其是移动端,可以使体验更接近于原生app。

缺点

  • 前端响应较慢。如果是客户端渲染,前端还要进行拼接字符串的过程,需要耗费额外的时间,不如服务器端渲染速度快。
  • 不利于SEO。虽然Chrome和部分浏览器开始对页面进行JS的执行后再抓取,但目前大部分浏览器对于SPA都是不认的,只是记录了一个页面,所以SEO很差。因为服务器端可能没有保存完整的html,而是前端通过js进行dom的拼接,那么爬虫无法爬取信息。

使用服务端渲染

服务端渲染有很多方式都能够实现:

JSP(JavaServer Pages)

传统的前后端统一式开发,将前端代码放到后台项目中,使用JSP进行数据拼接,这也是服务端渲染的一种实现方式。因其开发效率及体验都不是很好,所以我们现在的项目很少使用。

express + ejs

我们可以使用express + ejs搭建一个node服务器,将前端HTML代码编写成ejs的专用语法,涉及到需要数据请求的地方,我们向后台发送请求,获取到数据后将内容返回给ejs进行HTML拼接,最终再返回给客户端。

express+ejs只是一个例子,我们可以使用与其功能类似的其他框架,比如koa等。

express + react

react框架的项目,想使用ssr,可以使用react-dom/serverrenderToString()方法将React组件转化为HTML代码,从而实现服务端渲染。

import fs from 'fs';
import path from 'path';
import express from 'express';

import React from 'react';
import { StaticRouter } from "react-router-dom";
import { renderToString } from 'react-dom/server';
import App from '../src/App';

const app = express();

app.get('/*', (req, res) => {
    const renderedString = renderToString(
        <StaticRouter>
            <App></App>
        </StaticRouter>
    );

    fs.readFile(path.resolve('index.html'), 'utf8', (error, data) => {
        if (error) {
            res.send(`

Server Error

`
); return false; } res.send(data.replace('
'
, `
${renderedString}
`
)); }) }); app.listen(3000);

vue + nuxt

vue框架的项目,使用nuxt就很方便了,我们只需要按照nuxt的脚手架创建好项目结构,然后就可以按照vue的开发方式进行开发了。
nuxt支持SSR服务端渲染模式SSG静态生成模式,如果说我们的页面需要提前动态获取数据并进行拼接,我们就需要使用服务端渲染模式;如果说我们的页面静态的东西比较多,动态数据不需要考虑SEO,那么我们可以选择静态生成模式,相当于使用预渲染,不需要node服务器也能够提升SEO。
需要注意的是,nuxt为我们提供了比原生vue更多的生命周期:
服务端渲染_第1张图片

  • nuxtServerInit:服务端初始化,用于在页面渲染之前将数据存储到vuex中,比如用户信息,注意第一个参数是vuex的上下文对象,第二个参数是nuxt上下文对象
  • Route Middleware:路由中间件,在初始化页面组件前调用,用于设置或检查路由条件或者重定向。此中间件分为三类,按照顺序调用,一是渲染Global(在nuxt.config.js中定义),二是Layout整体布局(在layout中定义),三是Page页面组件(在Page component中定义)
  • validate,校验钩子,在渲染页面组件前调用,用于校验动态路由参数的有效性,需要返回truefalse
  • asyncData:异步获取数据,在渲染组件之前获取数据用,好比你在vue组件中用created获取数据一样,不同的是asyncData是在服务端执行的,所以在此钩子中不能获取vue组件的this对象。还有要注意的是:asyncData只是在首屏的时候调用一次(即页面渲染之前,所以事件触发不了它)
  • beforeCreate和createdvue实例的创建和创建前的钩子函数,与vue不同的是nuxt会在服务端和客户端都调用。
  • fetch:与asyncData类似,不同的是它不会设置组件的数据,因为此钩子是在vue实例创建后调用的,所以在这里可以获取到vue的this对象。
  • mounted&其他钩子:与vue剩余的生命周期一致,在客户端执行。
    <template>
      <div class="news-wrap">
        <div class="title-wrap">
          {{ title }}
        </div>
        <div
          v-for="(item, index) in newsList"
          :key="index"
          class="news-item"
        >
          <div class="title">
            {{ item.title }}
          </div>
          <div class="author">
            {{ item.author }}
          </div>
          <div class="date">
            {{ item.date }}
          </div>
          <div class="description">
            {{ item.description }}
          </div>
        </div>
      </div>
    </template>
    
    <script>
    import { getNewsList } from '../api'
    
    export default {
      data () {
        return {
          newsList: [],
          title: '新闻列表1'
        }
      },
      async fetch () {
        await getNewsList().then((res) => {
          console.log(res)
          if (res.code === 1) {
            // console.log(res, app)
            this.title = 'ssr新闻列表'
            this.newsList = res.data
          }
        })
      }
    }
    </script>
    

怎样选择?

之前看到网上一句话 ,觉得用在这里在合适不过:“抛开业务场景谈技术选型的都是耍流氓”。

适用于客户端渲染的项目:

  • 企业内部项目,管理平台这类不需要SEO的项目,使用客户端渲染能能够提高开发效率,减少服务器资源占用;
  • 强交互项目:对于交互比较多,数据不是很固定的项目,使用客户端渲染,能够让用户更临近于原生APP体验;

适用于服务端渲染的项目:

  • 官网 / 博客网站 / 营销类网站:这些网站对SEO和首屏渲染速度更加注重,所以服务端渲染会是较好的选择;

综合方案?

现在有技术可以实现服务端渲染和客户端渲染结合,比如next.js,对于网站部分需要SEO和首屏渲染速度的页面,我们是使用服务端渲染,对于其他交互性强或者是不需要SEO的页面,我们使用静态构成,从而减少服务器压力,提高交互体验。

你可能感兴趣的:(服务端渲染)