使用 Rendertron 进行动态呈现

2019 年 1 月 31 日,星期四

很多前端框架依赖 JavaScript 来显示内容。这意味着 Google 可能需要一段时间才能将您的内容编入索引或更新已编入索引的内容。

我们在今年的 Google I/O 大会上讨论的一种临时解决方法动态呈现。实现动态呈现的方法有很多种。这篇博文将介绍一个使用 Rendertron(一种基于无头 Chromium 的开源解决方案)进行动态呈现的实现示例。

哪些网站应考虑动态呈现?

并非所有访问您网站的搜索引擎或社交媒体漫游器都可以运行 JavaScript。例如,Googlebot 就可能需要花点时间来运行您的 JavaScript,而且还有一些限制

动态呈现对于会经常变更且需要依赖 JavaScript 才能显示的内容非常有用。混合呈现(例如 Angular Universal)可能有助于改进您网站上的用户体验(特别是首次有效渲染时间)。

动态呈现的工作方式

动态呈现的运作方式

动态呈现是指针对特定用户代理在客户端呈现的内容和预呈现的内容之间进行切换。

您需要使用呈现器来执行 JavaScript 并生成静态 HTML。Rendertron 是一个使用无头 Chromium 呈现内容的开放源代码项目。单页应用通常会在后台加载数据或推迟某些工作以呈现其内容。Rendertron 会通过一些机制来确定网站何时呈现完毕。它会一直等到所有网络请求均已完成且所有工作均已处理完毕。

这篇博文涵盖以下内容:

  1. 查看一个示例 Web 应用
  2. 设置一台小型 express.js 服务器以提供这个 Web 应用
  3. 安装 Rendertron 并将其配置为中间件以进行动态呈现

示例 Web 应用

“kitten corner”Web 应用使用 JavaScript 从 API 加载各种猫咪图片并将它们显示在网格中。

网格中的可爱猫咪图片以及一个用于显示更多内容的按钮 - 这个 Web 应用真的是一应俱全!

所用的 JavaScript 如下:

const apiUrl = 'https://api.thecatapi.com/v1/images/search?limit=50';
   const tpl = document.querySelector('template').content;
   const container = document.querySelector('ul');
   function init () {
     fetch(apiUrl)
     .then(response => response.json())
     .then(cats => {
       container.innerHTML = '';
       cats
         .map(cat => { const li = document.importNode(tpl, true); li.querySelector('img').src = cat.url; return li;
         }).forEach(li => container.appendChild(li));
     })
   }
   init();
   document.querySelector('button').addEventListener('click', init);

该 Web 应用使用的是在 Googlebot 中尚不受支持的现代 JavaScript (ES6)。我们可以使用移动设备适合性测试检查 Googlebot 能否看到相应内容:

移动设备适合性测试表明:该网页适合在移动设备上浏览,但屏幕截图中未显示任何猫咪!有标题和按钮,但没有任何猫咪图片。

虽然此问题很容易解决,但最好还是了解一下如何设置动态呈现。借助动态呈现,您无需更改网络应用代码就能让 Googlebot 看到猫咪图片。

设置服务器

为了提供这个 Web 应用,我们使用 express(一个 node.js 库)来构建网络服务器。

服务器代码如下所示(点击此处可查看完整的项目源代码):

const express = require('express');
const app = express();
const DIST_FOLDER = process.cwd() + '/docs';
const PORT = process.env.PORT || 8080;
// Serve static assets (images, css, etc.)
app.get('*.*', express.static(DIST_FOLDER));
// Point all other URLs to index.html for our single page app
app.get('*', (req, res) => {
  res.sendFile(DIST_FOLDER + '/index.html');
});
// Start Express Server
app.listen(PORT, () => {
  console.log(`Node Express server listening on https://localhost:${PORT} from ${DIST_FOLDER}`);
});

您可以利用实例练练手 - 如果您使用的是新型浏览器,则应该会看到一堆猫咪图片。如需从计算机上运行项目,您需要使用 node.js 运行如下命令:

npm install --save express rendertron-middleware
node server.js

然后将浏览器指向 https://localhost:8080。 接着就可以设置动态呈现了。

部署 Rendertron 实例

Rendertron 会运行一台服务器,以通过使用无头 Chromium 接收网址并为该网址返回静态 HTML。我们将遵循 Rendertron 项目中的建议并使用 Google Cloud Platform

用于创建新的 Google Cloud Platform 项目的表单。

请注意,您可以先从无需付费即可使用的层级着手;如果在生产环境中使用此设置,您可能需要根据 Google Cloud Platform 定价支付相关费用。

  1. Google Cloud Console 中创建一个新项目。记下输入字段下方的“项目 ID”。
  2. 按照相应文档中的说明安装 Google Cloud SDK 并登录。
  3. 使用如下命令行从 GitHub 克隆 Rendertron 代码库:
    git clone https://github.com/GoogleChrome/rendertron.git
    cd rendertron
  4. 运行如下命令以安装依赖项并在计算机上构建 Rendertron:
    npm install && npm run build
  5. 在 rendertron 目录中创建一个名为 config.json 且包含如下内容的新文件以启用 Rendertron 的缓存:
    { "datastoreCache": true }
  6. 从 rendertron 目录中运行如下命令。将 YOUR_PROJECT_ID 替换为您在第 1 步中记下的项目 ID。
    gcloud app deploy app.yaml --project YOUR_PROJECT_ID
  7. 选择一个区域并确认部署。等待此过程完成。
  8. 输入网址 YOUR_PROJECT_ID.appspot.com。您应该会看到包含一个输入字段和几个按钮的 Rendertron 的界面。
部署到 Google Cloud Platform 之后的 Rendertron 界面

当您看到 Rendertron 网页界面时,即表示您已成功部署了自己的 Rendertron 实例。记下项目的网址 (YOUR_PROJECT_ID.appspot.com),因为在此过程的下一部分中会用到它。

将 Rendertron 添加到服务器

网络服务器使用的是 express.js,而 Rendertron 具有 express.js 中间件。在 server.js 文件的目录中运行如下命令:

npm install --save rendertron-middleware

此命令会从 npm 安装 rendertron-middleware,以便我们将其添加到服务器:

const express = require('express');
const app = express();
const rendertron = require('rendertron-middleware');

配置漫游器列表

Rendertron 会使用 user-agent HTTP 标头来确定请求是来自漫游器还是来自用户的浏览器。它会参照一个妥善维护的漫游器用户代理列表进行比较。默认情况下,此列表不包含 Googlebot,因为 Googlebot 可以执行 JavaScript。为使 Rendertron 也能呈现 Googlebot 请求,请将 Googlebot 添加到用户代理列表中:

const BOTS = rendertron.botUserAgents.concat('googlebot');
const BOT_UA_PATTERN = new RegExp(BOTS.join('|'), 'i');

Rendertron 稍后会将 user-agent 标头与此正则表达式进行比较。

添加中间件

为了将漫游器请求发送到 Rendertron 实例,我们需要向 express.js 服务器添加中间件。该中间件会检查发出请求的用户代理,并会将来自已知漫游器的请求转发到 Rendertron 实例。请将如下代码添加到 server.js(别忘了要将“YOUR_PROJECT_ID”替换为您的 Google Cloud Platform 项目 ID):

app.use(rendertron.makeMiddleware({
  proxyUrl: 'https://YOUR_PROJECT_ID.appspot.com/render',
  userAgentPattern: BOT_UA_PATTERN
}));

请求示例网站的漫游器会从 Rendertron 接收静态 HTML,因此漫游器不需要运行 JavaScript 就能显示相应内容。

测试我们的设置

若要测试 Rendertron 设置是否成功,请再次运行移动设备适合性测试。

移动设备适合性测试表明:该网页适合在移动设备上浏览,而且现在屏幕截图中会显示所有猫咪!

与第一次测试不同,在此次测试中猫咪图片是可以看到的。在“HTML”标签页中,我们既可看到 JavaScript 代码生成的所有 HTML,也可看到 Rendertron 已经不再需要 JavaScript 来显示内容。

总结

您在不更改 Web 应用的情况下创建了一项动态呈现设置。通过这些更改,您可以向抓取工具提供静态 HTML 版 Web 应用。