![](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
來源:慕課網
本文原創釋出于慕課網 ,轉載請注明出處,謝謝合作