«

ssr(服务端渲染)

emer 发布于 2020-7-9 17:35   3439 次阅读     


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提供了两种服务端渲染函数,如下:

  1. renderToString:将 React Component 转化为 HTML 字符串,生成的 HTML 的 DOM 会带有额外属性:各个 DOM 会有data-react-id属性,第一个 DOM 会有data-checksum属性。

  2. renderToStaticMarkup:将 React Component 转化为 HTML 字符串,但是生成 HTML 的 DOM 不会有额外属性,从而节省 HTML 字符串的大小。

所以这里我们一般使用renderToStaticMarkup函数. 同理在实际业务场景中我们也会写2套代码来实现ssr.


2.使用谷歌rendertron实现服务端渲染


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);