自建 prerender 服务来对 SPA 项目做 SEO 优化

自建 prerender 服务来对 SPA 项目做 SEO 优化

小小孩
2022-12-26 / 2 评论 / 413 阅读 / 正在检测是否收录...

背景

单页面应用使用浏览器动态解析 JS,呈现出最终的页面,用户体验比较好,网站性能也提高不少。但网络爬虫并不会动态解析 Js (谷歌比较先进可以解析 JS),所以访问所有未处理的单页面应用 URL 得到的只会是项目入口(index.html)文件中的代码,不能得到具体的内容,对 Seo 的优化极其的不友好。为了优化项目 Seo,目前主要有两个方案:服务端渲染(Server Side Rendering)、预渲染(Prerending)。使用服务端渲染的话 需要对项目进行改造,也违背了开始做 SPA 的初衷,这里就不做深入了,这里提供了一种专门针对搜索引擎爬虫的渲染 SEO 优化

预渲染

使用 Prerender.io 做网站预渲染,可以将网站页面渲染之后再返回给网络爬虫,间接完成网页的解析。 Prerender 相较于其他的解决方案,配置相对要简单一些,不用修改项目源码,代码零侵入,是一个不错的解决方案。可以使用访问 htttps:/prerender.io 就可以按照步骤接入,但是这事商业化的方案,使用量较多时就需要付费了,免费的计划 适合小型项目,看个人需求。另一种是可以自建 prerender 服务 可以为多个项目进行 预渲染

自建 Prerender 服务

选用的是 Prerender.io 开源渲染方案 再加上自己的优化处理。这里就主要介绍搭建基于 Centos 7 和 Nginx 环境的 Prerender 渲染服务,完成项目中网页的预渲染

安装 Prerender 服务

  1. 在服务器上安装 Node 环境
  2. 在服务器上安装 Chrome
  3. 在 Node 部署 Perender 服务

安装 Node 环境

第一步安装 Node 环境 我就不多赘述了 网上教程一大堆

安装 Chrome

Centos 系统下安装
  1. 配置 yum 源 因为国内无法访问 Google,所以需要自己配置 yum 源,在目录 /etc/yum.repos.d/ 下新建google-chrome.repo文件

    cd /ect/yum.repos.d/
    touch google-chrome.repo
  2. 写入内容 google-chrome.repo

    [google-chrome]
    name=google-chrome
    baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
    enabled=1
    gpgcheck=1
    gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
  3. 安装运行

    # 国内推荐
    yum -y install google-chrome-stable --nogpgcheck
  4. 检查安装
    安装成功后,Chrome的安装路径应该是 /opt/google/chrome .
    默认情况下,root用户不能直接运行chrome,所以可以 使用 adduser www新建另一个用户来运行,这里新建了 新的 www 用户。

    cd /opt/google/chrome
    su www
    ./chrome
debian 系统下安装
  1. 需要通过apt在终端中运行以下命令来确保您的系统是最新的

    sudo apt update
    sudo apt upgrade
  2. 从官方存储库安装Google Chrome,需要添加Google的GPG密钥:

    wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
  3. 将Google Chrome存储库添加到您的Debian系统

    sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
  4. 使用以下命令安装Google Chrome浏览器64位稳定版

    sudo apt update
    sudo apt install google-chrome-stable

其实不一定非要安装 Chrome ,开源的 chromium 也行

  1. 安装

    sudo apt update
    sudo apt install chromium
  2. 找出位置 一般在 /usr/bin/chromium

    which chromium
  3. 配置项目的chrome 地址

    把得到的地址填入 chromeLocation

    const server = prerender({
     chromeLocation: '/usr/bin/chromium'
    });
    

部署 Perender 服务

本地新建项目

└─node_modules
└─index.js
└─package.json
  1. 先安装 prerender 木块

    npm i prerender
  2. 编写 index.js

    index.js
    const prerender = require('prerender');
    const server = prerender({
      port:26666
    });
    server.start();
  3. 后台运行

    nohup node ./server.js &

如此就在 本地 26666 端口 运行了。

安装中间件,这里使用 nginx 作为处理中间件

server {
    listen 80;
    server_name example.com;
    root   /path/to/your/root;
    index  index.html;

    location / {
        try_files $uri @prerender;
    }

    location @prerender {
        # 如果使用 商业的 prerender.io 需要 将 YOUR_TOKEN替换为你的个人token
        proxy_set_header X-Prerender-Token YOUR_TOKEN;
        
        set $prerender 0;
        # 这里判断哪些爬虫需要走预渲染
        if ($http_user_agent ~* "googlebot|bingbot|yandex|baiduspider") {
            set $prerender 1;
        }
        # 测试用
        if ($args ~ "_escaped_fragment_") {
            set $prerender 1;
        }
        if ($http_user_agent ~ "Prerender") {
            set $prerender 0;
        }
        # 静态文件不需要预渲染
        if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
            set $prerender 0;
        }
        
        #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
        resolver 8.8.8.8;

        if ($prerender = 1) {
            # 后续自建将 http://service.prerender.io 替换为自己的prerender服务,如 http://127.0.0.1:26666
            set $prerenderServer "http://service.prerender.io";
            rewrite .* /$scheme://$host$request_uri? break;
            proxy_pass $prerenderServer;
        }
        if ($prerender = 0) {
            rewrite .* /index.html break;
        }
    }
}

nginx 配置如上,看注释 自及修改自己的配置,检测nginx配置,并重启nginx。

至此,Prerender 服务已经安装并启动成功。

测试

通过curl命令测试

curl http://www.example.com/?_escaped_fragment_=

一般情况下就可看到 实际运行渲染的 html 结构了

也可以 在网上找一个 在线模拟百度爬虫的网站 对网站进行模拟访问一下,看看 html 结构

其他优化

缓存优化

同一个页面 每次 进来 都要进过chrome 来进行渲染,这很影响性能,这时可以通过缓存在优化,在有效时间内,如果有缓存直接取缓存数据返回
需要编写缓存处理
在 node 项目中安装 cache-manager-fs 模块

npm i cache-manager-fs

添加 插件 文件夹 及文件

└─node_modules
└─plugins
│  └─fs-cache.js
└─index.js
└─package.json
fs-cache.js
var cacheManager = require('cache-manager');
var fsStore = require('cache-manager-fs');
module.exports = {
    init: function () {
        this.cache = cacheManager.caching({
            store: fsStore,
            maxsize: process.env.CACHE_MAXSIZE || 500 * 1000 * 1000 * 1000,
            ttl: process.env.CACHE_TTL || 24*60*60, /*seconds*/
            path: 'cache',
            preventfill: true
        });
    },

    requestReceived: function (req, res, next) {
        this.cache.get(req.prerender.url, function (err, result) {
            if (!err && result) {
                req.prerender.cacheHit = true;
                console.log('cacheHit 缓存命中', req.prerender.url)
                res.send(200, result);
            } else {
                next();
            }
        });
    },

    beforeSend: function (req, res, next) {
        if (!req.prerender.cacheHit && req.prerender.statusCode == 200) {
            this.cache.set(req.prerender.url, req.prerender.content);
        }
        next();
    }
};

其中 maxsize ttl path 可以通过 环境变量设置也可以 使用默认设置

相应的 index.js 也需要小小修改
const prerender = require('prerender');

const fsCache = require('./plugins/fs-cache.js');

const server = prerender({
  port:26666
});

server.use(fsCache)

server.start();

重启 服务就可以实现了

接口保护

如果你的服务需要收到保护,防止别人恶意使用 可以像 prerender.io 添加接口 token 保护

修改 index.js
const prerender = require('prerender');

const fsCache = require('./plugins/fs-cache.js');


const server = prerender({
  port:26666
});

server.use({
  requestReceived: (req, res, next) => {
    const canPassToken = [] //这里放 可以通过的token
    const token = req.headers['x-prerender-token']; // 这里使用与 prerender.io 一样的头部字段名
    if (!canPassToken.includes(token)) { // 如果 token 不在 数据里 则返回403
       res.send(403)
    } else {
      next()
    }
  },
})

server.use(fsCache)

server.start();

0

评论 (2)

取消
  1. 头像
    ww
    Windows 10 · Google Chrome

    赞,试试

    回复
  2. 头像
    l
    Windows 10 · Google Chrome

    画图

    回复