AMP

重要提示:此文档不适用于您当前选择的格式 ads

amp-access

描述

提供 AMP 付费墙和订阅支持。

 

必需脚本

<script async custom-element="amp-access" src="https://cdn.ampproject.org/v0/amp-access-0.1.js"></script>

AMP Access 或“AMP 付费墙和订阅支持”使发布商能够控制读者可以访问哪些内容,以及基于读者的订阅状态、浏览次数和其他因素的限制。

与 amp-subscriptions 的关系

amp-subscriptions 扩展提供了与 amp-access 类似的功能。但是,它支持更专业的访问付费墙协议。一些值得注意的差异是

  1. amp-subscriptions 授权响应类似于 amp-access 授权,但它是严格定义和标准化的。
  2. amp-subscriptions 扩展允许为页面配置多个服务,以参与访问/付费墙决策。它们并行执行,并根据哪个服务返回肯定响应进行优先级排序。
  3. 允许 AMP 查看器根据与发布商的独立协议,为 amp-subscriptions 提供签名的授权响应,作为访问证明。
  4. amp-subscriptions 中,内容标记是标准化的,允许应用程序和爬虫轻松检测优质内容部分。

由于标记的标准化、多提供商支持和改进的查看器支持,建议新的发布商和付费墙提供商的实现使用 amp-subscriptions

解决方案

建议的解决方案使发布商可以控制以下决策和流程

  • 创建和维护用户
  • 控制计量(允许一定数量的免费浏览)
  • 负责登录流程
  • 负责对用户进行身份验证
  • 负责访问规则和授权
  • 在每个文档的基础上灵活控制访问参数

该解决方案包括以下组件

  1. AMP 阅读器 ID:由 AMP 生态系统提供,这是 AMP 所见的读者唯一标识符。
  2. 访问内容标记:由发布商编写,定义文档的哪些部分在哪些情况下可见。
  3. 授权端点:由发布商提供,返回解释读者可以消费文档的哪一部分的响应。
  4. 回传端点:由发布商提供,用于发送文档的“浏览”展示。
  5. 登录链接和登录页面:允许发布商对读者进行身份验证,并将他们的身份与 AMP 阅读器 ID 连接起来。

Google AMP Cache 将文档返回给读者,其中一些部分使用访问内容标记进行模糊处理。AMP 运行时调用授权端点,并使用响应来隐藏或显示由访问内容标记定义的不同部分。在文档显示给读者后,AMP 运行时会调用回传端点,发布商可以使用该端点更新倒计时仪表(已使用的免费浏览次数)。

该解决方案还允许发布商在 AMP 文档中放置一个登录链接,该链接启动登录/订阅页面,发布商可以在该页面对读者进行身份验证,并将读者在其系统中的身份与 AMP 阅读器 ID 关联起来。

在其基本形式中,此解决方案将完整的(尽管是模糊的)文档发送给读者,并且仅根据授权响应显示/隐藏受限制的部分。但是,该解决方案还提供了“服务器”选项,其中受限制的部分可以从初始文档交付中排除,并且仅在确认授权后下载。

支持 AMP Access 需要发布商实施上述组件。需要访问内容标记和授权端点。回传端点和登录页面是可选的。

AMP 阅读器 ID

为了帮助访问服务和用例,AMP Access 引入了阅读器 ID 的概念。

阅读器 ID 是由 AMP 生态系统创建的匿名且唯一的 ID。它对于每个阅读器/发布商对都是唯一的 - 阅读器对两个不同的发布商的识别是不同的。这是一个不可逆的 ID。阅读器 ID 包含在所有 AMP/发布商通信中,并且具有非常高的熵。发布商可以使用阅读器 ID 来识别阅读器,并将其映射到他们自己的身份系统。

阅读器 ID 在用户设备上构建,旨在长期存在。但是,它遵循正常的浏览器存储规则,包括隐身窗口的规则。阅读器 ID 的预期生命周期为两次使用之间 1 年,或者直到用户清除他们的 cookie 为止。阅读器 ID 当前不在设备之间共享。

阅读器 ID 的构建方式与用于构建此处描述的 ExternalCID 的机制类似 此处。一个示例阅读器 ID 是 amp-OFsqR4pPKynymPyMmplPNMvxSTsNQob3TnK-oE3nwVT0clORaZ1rkeEz8xej-vV6

AMP 访问和 Cookie

发布商可以使用他们自己的身份验证 cookie,或者他们可以依赖阅读器 ID,或者两者结合使用。

访问内容标记

访问内容标记根据从授权端点返回的授权响应确定哪些部分可见或隐藏。它是通过特殊的标记属性描述的。

授权端点

授权是由发布商提供的端点,由 AMP 运行时或 Google AMP Cache 调用。这是一个凭据 CORS GET 端点。此端点返回访问参数,内容标记可以使用这些参数来隐藏或显示文档的不同部分。

回传端点

回传是由发布商提供的端点,由 AMP 运行时或 Google AMP Cache 调用。这是一个凭据 CORS POST 端点。当读者开始查看文档时,AMP 运行时会自动调用此端点。此端点也在读者成功完成登录流程后调用。回传的主要目标之一是供发布商更新计量信息。

回传是可选的。可以通过将 noPingback 配置属性设置为 true 来禁用它。

登录页面由发布商实现并提供,并由 AMP 运行时调用。它通常显示为浏览器对话框。

当读者点击登录链接时触发登录页面,发布商可以将登录链接放置在文档中的任何位置。

规范 v0.1

配置

所有端点都在 AMP 文档中配置为文档 HEAD 中的 JSON 对象

<script id="amp-access" type="application/json">
  {
    "property": value,
    ...
  }
</script>

此配置中定义了以下属性

属性 描述
authorization <URL> 授权端点的 HTTPS URL。
pingback <URL> 回传端点的 HTTPS URL。
noPingback true/false 为 true 时,禁用回传。
login <URL> 或
<Map[string, URL]>
登录页面的 HTTPS URL 或用于不同类型登录页面的 URL 集。
authorizationFallbackResponse <object> 如果授权失败,则用作授权响应的 JSON 对象。
authorizationTimeout <number> 授权请求被视为失败的超时时间(以毫秒为单位)。默认值为 3000。仅在开发环境中允许大于 3000 的值。
type "client" 或 "server" 默认值为“client”。“server”选项正在设计讨论中,这些文档将在准备就绪后更新。
namespace string 默认为空。如果指定了多个访问提供程序,则必须使用命名空间。

<URL> 值指定带有替换变量的 HTTPS URL。替换变量将在下面的访问 URL 变量部分中详细介绍。

以下是一个 AMP 访问配置的示例

<script id="amp-access" type="application/json">
  {
    "authorization": "https://pub.com/amp-access?rid=READER_ID&url=SOURCE_URL",
    "pingback": "https://pub.com/amp-ping?rid=READER_ID&url=SOURCE_URL",
    "login": "https://pub.com/amp-login?rid=READER_ID&url=SOURCE_URL",
    "authorizationFallbackResponse": {"error": true}
  }
</script>

多个访问提供商

可以使用数组而不是单个对象来指定多个访问提供程序,并为每个条目提供一个 namespace

<script id="amp-access" type="application/json">
  [
    {
      "property": value,
      ...
      "namespace": value
    },
    ...
  ]
</script>

访问 URL 变量

在配置各种端点的 URL 时,发布商可以使用替换变量。这些变量的完整列表在 AMP 变量规范中定义。此外,此规范还添加了一些特定于访问的变量,例如 READER_IDAUTHDATA。下表描述了一些最相关的变量

变量 描述
READER_ID AMP 阅读器 ID。
AUTHDATA(field) 授权响应中字段的值。
RETURN_URL 由 AMP 运行时指定的返回 URL 的占位符,用于返回到登录对话框。
SOURCE_URL 此 AMP 文档的源 URL。如果该文档是从 CDN 提供的,则 AMPDOC_URL 将是 CDN URL,而 SOURCE_URL 将是原始源 URL。
AMPDOC_URL 此 AMP 文档的 URL。
CANONICAL_URL 此 AMP 文档的规范 URL。
DOCUMENT_REFERRER 引用 URL。
VIEWER AMP 查看器的 URL。
RANDOM 一个随机数。有助于避免浏览器缓存。

以下示例展示了使用阅读器 ID、规范 URL、引用信息和随机缓存清除器扩展的 URL

https://pub.com/access?
   rid=READER_ID
  &url=CANONICAL_URL
  &ref=DOCUMENT_REFERRER
  &_=RANDOM

AUTHDATA 变量可用于 Pingback 和登录 URL。它允许将授权响应中的任何字段作为 URL 参数传递。例如,AUTHDATA(isSubscriber)。也允许嵌套表达式,例如 AUTHDATA(other.isSubscriber)。如果使用命名空间,则可以将命名空间添加到字段前面,例如 AUTHDATA(anamespace.afield)

访问内容标记

访问内容标记描述了哪些部分可见或隐藏。它由两个 AMP 属性组成:amp-accessamp-access-hide,可以放置在任何 HTML 元素上。

amp-access 属性提供了一个表达式,该表达式根据授权端点返回的授权响应产生 true 或 false。结果值指示元素及其内容是否可见。

amp-access 值是以类似 SQL 的语言定义的布尔表达式。语法在 附录 A 中定义。定义如下

<div amp-access="expression">...</div>

属性和值是指授权端点返回的授权响应的属性和值。这提供了一个灵活的系统来支持不同的访问场景。如果使用命名空间,只需将命名空间添加到属性名称前面,例如 anamespace.aproperty

amp-access-hide 属性可用于在收到授权响应之前乐观地隐藏该元素,这可以显示它。它提供了“默认不可见”的语义。稍后,授权响应可能会撤销此默认值并使该部分可见。当省略 amp-access-hide 属性时,该部分将默认显示/包含。amp-access-hide 属性只能与 amp-access 属性结合使用。

<div amp-access="expression" amp-access-hide>...</div>

如果授权请求失败,则不会评估 amp-access 表达式,并且部分是否可见或隐藏由文档最初提供的 amp-access-hide 属性的存在决定。

我们可以根据需要扩展 amp-access-* 属性集,以支持不同的混淆和渲染需求。

如果授权请求失败,并且文档中未指定“authorizationFallbackResponse”响应,则不会评估 amp-access 表达式,并且部分是否可见或隐藏将由文档最初提供的 amp-access-hide 属性的存在决定。

以下示例根据订阅状态显示登录链接或完整内容

<header>
  Title of the document
</header>

<div>
  First snippet in the document.
</div>

<div amp-access="NOT subscriber" amp-access-hide>
  <a on="tap:amp-access.login">Become a subscriber now!</a>
</div>

<div amp-access="subscriber">
  Full content.
</div>

这里

  • subscriber 是授权端点返回的授权响应中的一个布尔字段。此部分默认隐藏,这是可选的。
  • 此示例选择乐观地显示完整内容。

以下是另一个示例,向读者显示关于计量状态的免责声明

<section amp-access="views <= maxViews">
  <template amp-access-template type="amp-mustache">
    You are reading article {{views}} out of {{maxViews}}.
  </template>
</section>

以下是一个示例,向高级订阅者显示其他内容

<section amp-access="subscriptonType = 'premium'">
  Shhh… No one but you can read this content.
</section>

授权端点

授权通过 AMP 访问配置部分中的 authorization 属性进行配置。它是一个带有凭据的 CORS GET 端点。有关如何保护此请求的信息,请参阅CORS 源安全

授权可以采用 访问 URL 变量部分中定义的任何参数。例如,它可以传递 AMP 阅读器 ID 和文档 URL。必须包含 READER_ID

此端点生成授权响应,该响应可在内容标记表达式中使用,以显示/隐藏内容的不同部分。

请求格式为

https://publisher.com/amp-access.json?
   rid=READER_ID
  &url=SOURCE_URL

响应是一个自由格式的 JSON 对象:它可以包含任何属性和值,但有一些限制。限制是

  • 属性名称必须符合 amp-access 表达式语法定义的限制(请参阅附录 A)。这主要意味着属性名称不能包含空格、破折号以及其他不符合“amp-access”规范的字符。
  • 属性值只能是以下类型之一:字符串、数字、布尔值。
  • 值也可以嵌套为具有相同类型值的对象:字符串、数字、布尔值。
  • 序列化的授权响应的总大小不能超过 500 字节。
  • 请确保响应不包含任何个人身份信息 (PII) 或个人数据。

以下是从授权端点返回的可能属性的一些想法

  • 计量信息:允许的最大浏览次数和当前浏览次数。
  • 读者是否已登录或订阅。
  • 更详细的订阅类型:基本版、高级版
  • 地理:国家/地区、区域、自定义发布区域

以下是当读者不是订阅者且每月计量 10 篇文章并且已浏览 6 篇文章时的响应示例

{
  "maxViews": 10,
  "currentViews": 6,
  "subscriber": false
}

以下是当读者已登录且拥有高级订阅类型时的响应示例

{
  "loggedIn": true,
  "subscriptionType": "premium"
}

此 RPC 可以在预渲染阶段调用,因此不应用于计量倒计时,因为读者可能永远不会实际看到该文档。

另一个重要的考虑因素是,在某些情况下,AMP 运行时可能需要每个文档展示多次调用授权端点。当 AMP 运行时认为读者的访问参数已发生显着变化时,例如在成功的登录流程之后,就会发生这种情况。

授权响应可被 AMP 运行时和扩展程序用于三个不同的目的

  1. 评估 amp-access 表达式时。
  2. 评估 <template> 模板(例如 amp-mustache)时。
  3. 使用 AUTHDATA(field) 向 pingback 和登录 URL 提供其他变量时。

AMP 运行时以带有凭据的 CORS 端点的形式调用授权端点。因此,它必须实现 CORS 协议。它应使用 CORS 源和源来源来限制对该服务的访问,如CORS 源安全中所述。此端点可以使用发布商 Cookie 来满足其需求。例如,它可以关联读者 ID 和发布商自己的用户身份之间的绑定。AMP 本身不需要知道这一点(并且最好不知道)。有关更多详细信息,请参阅AMP 阅读器 IDAMP 访问和 Cookie 文档。

AMP 运行时(或者更确切地说是浏览器)在调用授权端点时会观察缓存响应标头。因此,可以重用缓存的响应。这可能是也可能不是理想的。如果不是理想的,发布商可以使用适当的缓存控制标头和/或端点 URL 的 RANDOM 变量替换。

如果授权请求失败,AMP 运行时将回退到“authorizationFallbackResponse”(如果在配置中指定)。在这种情况下,授权流程将像往常一样继续进行,并使用“authorizationFallbackResponse”属性的值来代替授权响应。如果未指定“authorizationFallbackResponse”,则授权流程将失败,在这种情况下,将不会评估 amp-access 表达式,并且部分是否可见或隐藏将由文档最初提供的 amp-access-hide 属性的存在决定。

授权请求会自动超时,并在 3 秒后被假定为失败。

AMP 运行时在授权流程中使用以下 CSS 类

  1. 当授权流程开始时,在文档根目录上设置 amp-access-loading CSS 类,并在完成或失败时移除。
  2. 当授权流程失败时,在文档根目录上设置 amp-access-error CSS 类。

服务器选项中,对授权端点的调用由 Google AMP 缓存作为简单的 HTTPS 端点进行。这意味着在这种情况下,无法传递发布商的 Cookie。

回传端点

Pingback 通过 AMP 访问配置部分中的 pingback 属性进行配置。它是一个带有凭据的 CORS POST 端点。有关如何保护此请求的信息,请参阅CORS 源安全

Pingback URL 是可选的。可以使用 "noPingback": true 禁用它。

Pingback URL 可以采用 访问 URL 变量部分中定义的任何参数。例如,它可以传递 AMP 阅读器 ID 和文档 URL。必须包含 READER_ID

Pingback 不会生成响应 - AMP 运行时会忽略任何响应。

当读者开始查看文档并且读者成功完成登录流程后,将调用 Pingback 端点。

发布商可以选择使用 pingback

  • 来倒数页面免费浏览次数
  • 将 AMP 阅读器 ID 映射到发布商的身份,因为作为带有凭据的 CORS 端点,Pingback 可能包含发布商的 Cookie

请求格式为

https://publisher.com/amp-pingback?
   rid=READER_ID
  &url=SOURCE_URL

登录页面

登录页面的 URL 通过 AMP 访问配置部分中的 login 属性进行配置。

该配置可以指定单个登录 URL 或按登录类型键入的登录 URL 映射。单个登录 URL 的示例

{
  "login": "https://publisher.com/amp-login.html?rid={READER_ID}"
}

多个登录 URL 的示例

{
  "login": {
    "signin": "https://publisher.com/signin.html?rid={READER_ID}",
    "signup": "https://publisher.com/signup.html?rid={READER_ID}"
  }
}

该 URL 可以采用 访问 URL 变量部分中定义的任何参数。例如,它可以传递 AMP 阅读器 ID 和文档 URL。可以使用 RETURN_URL 查询替换来指定返回 URL 的查询参数,例如 ?ret=RETURN_URL。返回 URL 是必需的,如果未指定 RETURN_URL 替换,则将自动注入该 URL,默认查询参数名称为“return”。

登录页面只是一个普通的网页,没有其他特殊限制,只是它应该作为浏览器对话框正常工作。有关更多详细信息,请参阅登录流程部分。

请求格式为

https://publisher.com/amp-login.html?
   rid=READER_ID
  &url=SOURCE_URL
  &return=RETURN_URL

请注意,如果未指定 RETURN_URL 替换,则 AMP 运行时会自动添加“return”URL 参数。登录页面完成其工作后,它必须使用以下格式重定向回指定的“返回 URL”

RETURN_URL#success=true|false

请注意使用 URL 哈希参数“success”。该值是“true”或“false”,具体取决于登录是成功还是放弃。理想情况下,登录页面在可能的情况下会在成功或失败的情况下发送信号。

如果返回 success=true 信号,AMP 运行时将重复调用授权和 Pingback 端点以更新文档的状态并报告具有新访问配置的“视图”。

发布者可以选择将登录链接放置在文档内容的任何位置。

一个或多个登录 URL 通过 AMP Access 配置 部分中的“login”属性进行配置。

登录链接可以声明在任何允许“on”属性的 HTML 元素上。通常,这会是一个锚点或按钮元素。当配置单个登录 URL 时,格式如下:

<a on="tap:amp-access.login">Login or subscribe</a>

当配置多个登录 URL 时,格式为 tap:amp-access.login-{type}。示例:

<a on="tap:amp-access.login-signup">Subscribe</a>

当使用命名空间时,格式为 tap:amp-access.login-{namespace}tap:amp-access.login-{namespace}-{type}

AMP 不区分登录和订阅。这种区分可以由发布者使用多个登录 URL/链接或在发布者端进行配置。

amp-analytics 集成

amp-analytics 的集成在 amp-access-analytics.md 中有文档说明。

CORS 来源安全性

授权和回传端点是 CORS 端点,它们必须实现 AMP CORS 安全规范 中描述的安全协议。

计量

计量是指读者在一段时间内可以免费查看多次高级内容的系统。一旦达到配额,就会出现付费墙,读者将看到部分内容,其中包含向上销售的消息和注册/登录链接。例如,计量可以定义为“读者每月可以免费阅读 10 篇文章”。

AMP Access 提供了以下功能来实现计量访问:

  1. READER_ID 应用于存储计量信息。由于发布者不能依赖于始终能够在第三方上下文中设置 cookie,因此此数据应存储在服务器端。
  2. “读取计数”只能在回传端点中更新。
  3. 只有唯一的文档才能计入配额。即,刷新同一文档十次算作一次查看。为此,授权和回传端点可以注入 SOURCE_URL 或类似的 URL 变量。请参阅 访问 URL 变量

首次点击免费

Google 的首次点击免费(FCF)政策在此处进行了说明,最近的更新在此处进行了更详细的描述。

要实现 FCF,发布者必须(1)能够确定每次查看的引荐服务,以及(2)能够计算每个读者每天的查看次数。

AMP Access 规范涵盖了这两个步骤。可以使用 访问 URL 变量中描述的 DOCUMENT_REFERRER URL 替换将引荐来源注入到授权和回传 URL 中。可以使用服务器端的回传端点进行查看计数。这与 计量中描述的计量实现非常相似。

登录流程

AMP 以第一方窗口、弹出窗口或标签页的形式启动登录对话框。在可能的情况下,AMP 查看器应尝试在浏览器上下文中启动登录对话框,以便它可以利用顶级浏览器 API。

当读者激活登录链接时,AMP 运行时将启动登录流程,并按描述性地执行以下步骤:

  1. AMP 运行时或查看器为指定的登录 URL 打开登录对话框(第一方窗口)。该 URL 包含一个额外的“返回 URL”URL 查询参数(&return=RETURN_URL)。还可以将许多其他参数扩展到 URL 中,例如读者 ID。有关更多详细信息,请参阅登录页面部分。
  2. 发布者显示自由格式的登录页面。
  3. 读者按照登录步骤,例如输入用户名/密码或使用社交登录。
  4. 读者提交登录。发布者完成身份验证,设置 cookie,最后将读者重定向到先前请求的“返回 URL”。该重定向包含一个 URL 哈希参数 success,它可以是 truefalse
  5. 登录对话框遵循重定向到“返回 URL”。
  6. AMP 运行时重新授权文档。

只有步骤 2-5 需要发布者处理:发布者只提供他们自己的登录页面,并确保在完成后正确重定向。除了它应该作为对话框运行良好之外,对登录页面没有施加任何特殊约束。

像往常一样,读者 ID 应包含在对登录页面的调用中,并且可以由发布者用于身份映射。作为第一方窗口,发布者还将收到他们的 cookie,并能够设置它们。如果事实证明读者已经在发布者端登录,建议发布者立即使用 success=true 响应重定向回“返回 URL”。

AMP 词汇表

  • AMP 文档 - 符合 AMP 格式并通过 AMP 验证器验证的 HTML 文档。AMP 文档可由 Google AMP 缓存缓存。
  • AMP 验证器 - 对 HTML 文档执行静态分析并根据该文档是否符合 AMP 格式返回成功或失败的计算机程序。
  • AMP 运行时 - 执行 AMP 文档的 JavaScript 运行时。
  • Google AMP 缓存 - AMP 文档的代理缓存。
  • AMP 查看器 - 显示/嵌入 AMP 文档的 Web 或本机应用程序。
  • Publisher.com - AMP 发布者的站点。
  • CORS 端点 - 跨源 HTTPS 端点。有关更多信息,请参阅 https://mdn.org.cn/en-US/docs/Web/HTTP/Access_control_CORS。有关如何保护此类请求,请参阅 CORS 源安全
  • 读者 - 查看 AMP 文档的实际人员。
  • AMP 预渲染 - AMP 查看器可以利用预渲染,这会在显示隐藏文档之前渲染它。这可以显著提高性能。但重要的是要考虑到文档预渲染并不构成查看,因为读者可能永远不会实际看到该文档。

修订

  • 2016-09-02:“noPingback”配置属性和可选回传。
  • 2016-03-03:登录后重新发送回传 (v0.5)。
  • 2016-02-19:更正了示例,从 URL 变量替换中删除 {}
  • 2016-02-15:配置授权端点现在允许在授权失败时使用的“authorizationFallbackResponse”属性。
  • 2016-02-11:授权端点中的授权请求超时。
  • 2016-02-11:现在允许嵌套字段引用,例如 object.field
  • 2016-02-09:首次点击免费计量部分。
  • 2016-02-03:添加到CORS 源安全的“源”安全规范。
  • 2016-02-01:可以使用 RETURN_URL URL 替换自定义登录页面的“return”查询参数。

附录 A:“amp-access”表达式语法

最新的 BNF 语法可在 access-expr-impl.jison 文件中找到。

此语法的关键摘录如下:

search_condition:
    search_condition OR search_condition
  | search_condition AND search_condition
  | NOT search_condition
  | '(' search_condition ')'
  | predicate

predicate:
    comparison_predicate | truthy_predicate

comparison_predicate:
    scalar_exp '=' scalar_exp
  | scalar_exp '!=' scalar_exp
  | scalar_exp '<' scalar_exp
  | scalar_exp '<=' scalar_exp
  | scalar_exp '>' scalar_exp
  | scalar_exp '>=' scalar_exp

truthy_predicate: scalar_exp

scalar_exp: literal | field_ref

field_ref: field_ref '.' field_name | field_name

literal: STRING | NUMERIC | TRUE | FALSE | NULL

请注意,amp-access 表达式由 AMP 运行时和 Google AMP 缓存评估。这并不是发布者需要实现的规范的一部分。这里只是为了提供信息。

详细讨论

本节将详细解释 amp-access 规范背后的设计,并阐明设计选择。即将推出。

验证

请参阅 AMP 验证器规范中的amp-access 规则

需要更多帮助?

您已经阅读本文档十几次了,但它并没有真正涵盖您的所有问题?也许其他人也有同感:请在 Stack Overflow 上联系他们。

转到 Stack Overflow
发现错误或缺少功能?

AMP 项目强烈鼓励您的参与和贡献!我们希望您将成为我们开源社区的持续参与者,但我们也欢迎您对您特别感兴趣的问题做出一次性贡献。

转到 GitHub