
概述
欢迎来到我们关于 AMP Camp 的系列文章的最新一期,我们的演示展示了如何使用 AMP 创建一个交互式网站!在此系列文章中,我们将讨论我们在创建该网站时使用的方法和工具,以及我们制定的最佳实践。如果您有兴趣使用 AMP 创建一个交互式网站,我们希望您能学到一些东西!
在上一篇文章中,我们讨论了用于创建我们网站的构建流程。在这篇文章中,我们将讨论如何在客户端和服务器上使用模板。
AMP 通常用于通过链接分享平台即时提供页面,这被称为配对 AMP。在上一篇文章中,我们讨论了将 AMP 作为主要框架来构建整个网站的好处,这种方法称为AMP 优先。
在这篇文章中,我们将讨论如何在 AMP 优先网站中生成动态内容。这样,无论用户是从 AMP 缓存还是从网站的源访问页面,他们始终可以访问最新数据。
为了实现这一点,我们将探讨如何区分页面客户端渲染部分(不受缓存调解)和服务器端渲染部分(可以安全缓存)。
此外,为了简化我们的开发,我们将了解如何通过使用相同的模板引擎在客户端和服务器中使用模板。只要我们确保清楚地区分哪些部分必须由哪一层渲染,这可以使我们的代码更具可读性和可维护性。
作为回顾,让我们回顾一下如何在AMP 优先网站中访问内容。
AMP 优先网站中的动态内容
在AMP 优先网站中,用户可以通过两个不同的来源访问您的页面
- 网站来源:这些 AMP 页面由网站所有者托管。用户通常通过浏览网站的 URL 来访问这些页面。
- AMP 缓存来源:这些版本的 AMP 页面在被 Google 和 Bing 等搜索引擎发现后存储(例如在 cdn.ampproject.org 或 bing-amp.com)。用户通常在点击搜索结果或链接分享平台中的链接后访问这些页面。
在第一种情况下,网站所有者可以完全控制要应用的缓存策略,例如,通过使用传统的 HTTP 缓存策略和/或服务工作者。
对于从 AMP 缓存提供的页面,即使网站所有者可以强制更新(例如,通过使用更新缓存 API),默认情况下,缓存将遵循陈旧内容优先,验证后刷新模型。这包括在每次用户访问时检查原始位置的缓存标头(例如 max-age 和 s-max-age),并在资源陈旧时请求在后台获取新副本。出于该原因,一个用户可能会看到陈旧数据,直到已获取页面的最新版本。
对于许多网站,依赖 AMP 缓存的默认行为是可以接受的。例如,新闻网站上频繁访问的文章会自动保持新鲜,并且最多只有一位用户偶尔看到陈旧内容可能不是什么大问题。
电子商务网站通常有更严格的 UX 要求:即使向单个用户展示陈旧价格也可能阻止整个购买过程,或者更糟糕的是,会对用户对品牌的信任产生负面影响。
在影响较大的情况下,您可以对动态数据应用混合策略,以确保关键字段始终保持新鲜,同时利用缓存的速度优势来处理页面的非关键部分
- 客户端呈现的数据:对于关键字段(如价格),可以使用客户端请求。这些请求不受 AMP 缓存调解,并且可以通过使用动态 AMP 组件(如<amp-list>、<amp-bind>和<amp-access>)来实现。
- 服务器端呈现的数据:更改频率较低的页面非关键部分(如产品标题)可以在服务器中完全呈现。这通常通过将动态数据(来自数据库、API 等)与静态 HTML 模板相结合来实现。
因此,当提供页面时,生成的 HTML 代码将包含已填充的字段(非关键字段)以及对组件(如 <amp-list>)的调用,以用于客户端生成的关键字段。
在以下代码段中,用蓝色标记的部分是服务器端呈现的字段,而用红色标记的部分是稍后将在客户端解析的字段
<div class="product-details">
<h1>Stretched Jeans</h1>
<amp-list height="24" layout="fixed-height" src="/static/samples/json/product.json">
<template type="amp-mustache"> Price: ${{price}} </template>
</amp-list>
<p class=”product-description”>A classic choice for every day.</p>
</div>
Code language: HTML, XML (xml)
该代码看起来很简单,但这是后端完成的一些复杂工作的成果。接下来,我们将探讨如何通过使用流行的 Web 技术来实现这一点。
实施服务器端呈现策略
为了实践前面讨论的策略,我们将使用一种流行的后端技术:Node.js。
如前所述,对于页面的服务器端呈现部分,您需要某种方法来将从 API 和数据库获取的数据与静态 HTML 模板结合起来。在 Node.js 环境中,这通常通过 JS 模板引擎来实现。
市场上有许多可用的选项。在这篇文章中,我们将探讨一个流行的选项:mustache.js。除了易于实现和广泛使用之外,选择此模板引擎的一个优点是它已被 AMP 使用,通过名为 <amp-mustache> 的组件来呈现动态组件(如 <amp-list>)的响应。这让我们省去了学习另一项技术的精力,同时使我们的代码更加连贯和可读。
典型的 mustache 模板包含任意数量的 mustache 标签。默认情况下,这些标签用大括号编写(例如 {{price}} 和 {{availability}})。
即使这些模板易于编写,它们也是“无逻辑”的,这意味着您可以在模板中使用诸如 条件 之类的内容,但不能使用更多内容。大多数逻辑将在发送到这些模板以填充字段的数据对象中执行和包含。
对客户端和服务器使用相同模板引擎的挑战在于,我们将使用相同的标签来填充客户端和服务器端呈现的字段。这可能导致冲突。
在之前的示例代码中,如果我们在客户端和服务器中使用相同的默认 mustache 标签 {{ }},当引擎在服务器中运行时,并找到以下代码时
<div class="product-details">
<h1>${{product-title}}</h1>
<amp-list height="24" layout="fixed-height" src="/static/samples/json/product.json">
<template type="amp-mustache"> Price: ${{price}} </template>
</amp-list>
<p class=”product-description”>${{product-description}}</p>
</div>
Code language: HTML, XML (xml)
它将用用于填充模板的对象中相应属性的值替换每个动态字段。页面的最终版本将是
<div class="product-details">
<h1>Stretched Jeans</h1>
<amp-list height="24" layout="fixed-height" src="/static/samples/json/product.json">
<template type="amp-mustache"> Price: $50 </template>
</amp-list>
<p class=”product-description”>A classic choice for every day.</p>
</div>
Code language: HTML, XML (xml)
当 AMP 页面提供时,将发生以下序列:
- <amp-list> 将在页面加载时执行。
- 响应将传递给 <amp-mustache>。
- 由于价格已在后端填充,因此 mustache 找不到任何要解析的动态字段。
这阻止了我们确保价格始终最新鲜的目标。
为避免这种情况,您可以使用 自定义分隔符,在客户端和服务器中声明一组不同的标签。例如
- {{ }}: 对于由 <amp-mustache> 使用 <amp-list> 的结果呈现的字段。
- <% %>:用于服务器中由 mustache 填充的字段。
生成代码如下所示
<div class="product-details">
<h1><%product-title%></h1>
<amp-list height="24" layout="fixed-height" src="/static/samples/json/product.json">
<template type="amp-mustache"> Price: ${{price}} </template>
</amp-list>
<p class=”product-description”><%product-description%></p>
</div>
Code language: HTML, XML (xml)
通过在模板中组合这些分隔符,服务器将首先填充所有标记为 <% %> 的字段,而不会更改标记为 {{ }} 的字段,以便在 <amp-list> 执行后可由 <amp-mustache> 使用。
更进一步:根据用户代理提供不同版本的页面
对于 AMP 优先站点,可以通过向用户和抓取器提供两个不同版本的页面来应用附加优化
- 对于抓取器——混合客户端和服务器端渲染方法:之前讨论的策略仅可应用于来自 Google 抓取器的请求,通过使用反向 IP 查找验证 Googlebot。当抓取器获取 AMP 网址时,这些版本将被检索、存储并从 AMP 缓存中提供。
- 对于站点的原始用户——完全服务器端渲染方法:如果请求不是来自机器人,则可以完全服务器端渲染页面,以便从原始位置浏览该站点的用户无需不必要地因 <amp-list> 请求而产生任何附加延迟。
这样,由于在站点原始位置浏览的用户不会冒看到潜在陈旧内容的风险,因此无需对关键字段进行任何客户端请求。在这些情况下,所有内容都可以完全服务器端渲染,以避免产生客户端请求的潜在延迟。
以这种方式分解服务策略可确保从不同界面访问该站点的用户获得最佳性能。
摘要
在本文中,我们探讨了一种策略,以确保提供的 AMP 内容始终最新,方法是在同一页面中结合客户端和服务器端渲染的内容。
为此,我们探讨了如何使用流行的 Web 技术在客户端和服务器中使用模板:Node.js 和 mustache.js。
有关此模式应用的具体示例,您可以查看代码 AMP Camp。
产品详情页面是应用此技术的良好示例。它包含使用不同标签编写的字段的混合:{{ }},用于客户端请求,以及 <% %>,用于页面的服务器端渲染部分,如本指南中所述。
如果您想进一步实施,您可以分析请求的用户代理,并且仅向搜索引擎提供混合客户端和服务器端呈现的页面,同时向在您的原点上导航的用户提供这些页面的完全服务器端呈现版本。
撰写人:Google 网络生态系统顾问 Demián Renzulli