![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiY4ETZhJzNx0TZjJXdvN3PnBnaucHM0QTMfNDNxMGMllDO2ImZiJGN4cjZyQzMwYDOwQTMwQ2M1MTNtIjdvwVbvNmLn1WaopnLxMWaw9CXvwlOzBHd0hWPsJXdmYDM3YjZkJGNzQDNl1SOhRGOtETMiVWLlJTZ00yN3QGZlVWYh1DZpV3ZmITPlBXe0ZyPldWYtl2LcdXZpZ3Lc12bj5SZjVjL5h3byBnLzATLn1Wavw1LcpDc0RHaiojIsJye.jpg)
前言
我们都知道,
Vue和
React是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出自定义组件,进行生成
DOM和操作
DOM, 也就是我们常说的客户端渲染, 并且我们大部分主流的场景都是
SPA(单页面)应用, 而随着
SPA尤其是
React、
Vue、
Angular为代表的前端框架的流行,越来越多的
Web App使用的是客户端渲染。
使用
客户端渲染的优势在于
节省后端资源、
局部刷新、
前后端分离等,但随着应用的日益复杂,
首屏渲染时间不断变长, 并且存在严重的
SEO问题。
所以为了解决
SPA应用遇到的这些问题, 我们必须考虑
SSR:
服务端渲染(ssr) ,是指由服务器端完成页面的 HTML 结构拼接,并且直接将拼接好的 HTML 发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的处理技术。
对于服务端渲染的页面,服务端可以直接将带数据的内容通过 HTML 文本的形式返回,
搜索引擎爬虫可以轻易的获取页面内容,而对于客户端渲染的应用,客户端必须执行服务器返回的
Javascript才能得到正确的网页内容。目前,除
Google、
Bing支持
Javascript外(也会有一些限制),其他的大部分搜索引擎都不支持
Javascript,也就无法获取正确的网页内容。而本文要讲的技术方案,正是为了解决
SPA下的
SSR技术困境.接下来我们看看常用的ssr技术实现方案.
摘要
ssr(服务端渲染)技术实现方案
接下来笔者将列举几个常用的基于
vue/
react的服务端渲染方案,如下:
- 使用next.js/nuxt.js的服务端渲染方案
- 使用node+vue-server-renderer实现vue项目的服务端渲染
- 使用node+React renderToStaticMarkup实现react项目的服务端渲染
- 传统网站通过模板引擎来实现ssr(比如ejs, jade, pug等)
- 使用rendertron实现SPA项目的服务端渲染
以上是笔者之前实践过的方案, 最后一种方案笔者将在下面一节详细介绍, 因为
next/
nuxt是已有的服务端渲染解决方案,文档写的比较详细,这里笔者就不再做过多介绍了,这里我们简单介绍一下第二种和第三种方案.
1.使用node+vue-server-renderer实现vue项目的服务端渲染首先vue-server-renderer依赖node的api,所以只能运行在node环境, 我们需要先安装它:
npm install vue vue-server-renderer --save
在node中使用,代码如下:
const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>趣谈前端: {{ url }}</div>`
})
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(`
<!DOCTYPE html>
<html >
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`)
})
})
server.listen(8080)
当然实际情况比上面的案例要复杂很多, 我们可以专门写一个template.html,然后通过模板差值的方式导入后端数据,进而实现服务端渲染. 在使用这种方式的时候我们仍然要维护两套代码.
2.使用node+React renderToStaticMarkup实现react项目的服务端渲染使用这种方案和vue的方案类似, 只不过这里我们用了react自带的api来实现ssr,简单的实现代码如下:
var express = require('express');
var app = express();
var React = require('react'),
ReactDOMServer = require('react-dom/server');
var App = React.createFactory(require('./App'));
app.get('/', function(req, res) {
var html = ReactDOMServer.renderToStaticMarkup(
React.DOM.body(
null,
React.DOM.div({id: 'root',
dangerouslySetInnerHTML: {
__html: ReactDOMServer.renderToStaticMarkup(App())
}
})
)
);
res.end(html);
});
app.listen(80, function() {
console.log('running on port ' + 80);
});
以上使用了
renderToStaticMarkup, 我们都知道react-dom提供了两种服务端渲染函数,如下:
- renderToString :将 React Component 转化为 HTML 字符串,生成的 HTML 的 DOM 会带有额外属性:各个 DOM 会有data-react-id属性,第一个 DOM 会有data-checksum属性。
- renderToStaticMarkup :将 React Component 转化为 HTML 字符串,但是生成 HTML 的 DOM 不会有额外属性,从而节省 HTML 字符串的大小。
所以这里我们一般使用
renderToStaticMarkup函数. 同理在实际业务场景中我们也会写2套代码来实现
ssr.
使用谷歌rendertron实现服务端渲染
Google推出的
Rendertron使得
SPA也能够被不支持执行
Javascript的搜索引擎爬取渲染后的内容。其原理主要是通过使用
Headless Chrome在内存中执行
Javascript,并在得到完整内容后,将内容返回给客户端。
我们通常会将
Rendertron部署为一个独立的
HTTP服务,然后为
Web应用框架配置
Google官方提供的中间件或者在反向代理上添加相应路由规则,使得能够在检测到搜索引擎爬虫的
UA时,可以将请求代理给
Rendertron服务。笔者总结了一下其基实现本原理图,方便大家理解:
提供了两个主要 API:
- Render 用于渲染网站内容
- Screenshot 用于将网站内容截图
在 SEO 场景下我们使用的是
Render接口。
比如当客户端请求我们的网站时,我们服务端可以根据请求头
User Agent发现是否包含了
Baiduspider/2.0关键字,如果是, 那么可以认定为当前的客户端是一个百度爬虫此时可以将这个请求代理 Rendertron 服务的
/render/客户端请求地址
路由,让
Rendertron帮助执行网页内的
Javascript,并将最终内容返回给搜索引擎爬虫。
使用
Rendertron的好处在于我们可以不用考虑服务端渲染的部分,完全按照
SPA的模式开发项目,也不用为了兼容服务端渲染而写多余的兼容代码.
具体实现
首先我们需要安装Rendertron, 可以在
github中找到其安装和使用方法,在安装前最好先安装
docker, 目前
docker的最新版本以支持傻瓜式安装,所以安装启动都非常方便.
1.本地运行在安装好docker之后, 我们先全局安装rendertron:
npm install -g rendertron
然后我们需要安装谷歌浏览器(作为合格的开发都应该有谷歌浏览器~),然后就可以用它的cli来启动服务了,我们只需要在命令行执行如下命令:
rendertron
之后控制台会打印本地服务启动的地址,比如
localhost:3000
这个时候我们只需要在地址后面输入我们想渲染的网站即可:
localhost:3000:render/你的网站地址
,
如下图所示:
此时我们的
rendertron服务已经搭建完成, 接下来我们可以在服务端来实现ssr了,代码如下:
const koa = require('koa');
const app = new koa();
app.use(async (ctx, next) => {
ctx.type = "html";
if(/Baiduspider/2.0/g.ctx.header['user-agent']) {
// 是百度爬虫,则转发到rendertron服务中
ctx.redirect(`http://localhost:3000/render/${ctx.url}`)
}else {
// 渲染正常的路由页面
}
await next();
})
app.listen('80');
当然如果我们后端技术栈采用的是
express, rendertron有专门的中间件可以使用, 不仅仅可以拦截百度的爬虫,具体用法如下:
const express = require('express');
const rendertron = require('rendertron-middleware');
const app = express();
app.use(rendertron.makeMiddleware({
proxyUrl: 'http://your-rendertron-instance/render',
}));
// 正常的路由和页面渲染逻辑
app.use(...);
app.listen(81);
所以为了降低开发成本笔者建议可以采用
rendertron的方案, 单独部署一套服务器用来实现
ssr. 但是我们需要考虑当网站流量增加时的扩容问题,以及配置搭建反向代理或负载均衡等配套服务。
后期展望
后期笔者将会继续带大家探索大前端相关内容, 基本框架如下:
最后
如果想学习更多
H5游戏,
webpack,
node,
gulp,
css3,
javascript,
nodeJS,
canvas数据可视化等前端知识和实战,欢迎在《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。
作者:徐小夕
链接:http://www.imooc.com/article/details/id/310593
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作