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
类似的功能。但是,它支持更专门的访问付费墙协议。一些显著的差异是
amp-subscriptions
授权响应类似于 amp-access 授权,但它被严格定义和标准化。amp-subscriptions
扩展允许为页面配置多个服务以参与访问/付费墙决策。它们会同时执行,并根据哪个服务返回积极响应进行优先级排序。- AMP 观看者可以向
amp-subscriptions
提供基于与出版商的独立协议的已签名授权响应,作为访问证明。 - 在
amp-subscriptions
中,内容标记已标准化,允许应用和爬虫轻松检测高级内容部分。
由于标记的标准化、多提供商支持和改进的观看者支持,建议新的出版商和付费墙提供商实施使用 amp-subscriptions
。
解决方案
提议的解决方案赋予出版商对以下决策和流程的控制权
- 创建和维护用户
- 计量控制(允许一定数量的免费观看)
- 登录流程的责任
- 对用户进行身份验证的责任
- 访问规则和授权的责任
- 针对每个文档的访问参数的灵活性
该解决方案包含以下组件
- AMP 读者 ID:由 AMP 生态系统提供,这是 AMP 看到的读者的唯一标识符。
- 访问内容标记:由出版商编写,定义文档的哪些部分在哪些情况下可见。
- 授权端点:由出版商提供,返回解释读者可以消费文档的哪一部分的响应。
- 回传端点:由出版商提供,用于发送文档的“查看”印象。
- 登录链接和登录页面:允许出版商对读者进行身份验证,并将他们的身份与 AMP 读者 ID 关联起来。
Google AMP 缓存使用访问内容标记模糊一些部分,将文档返回给读者。AMP 运行时调用授权端点,并使用响应根据访问内容标记定义的内容隐藏或显示不同的部分。在文档向读者显示后,AMP 运行时会调用 Pingback 端点,发布商可以使用该端点更新倒计时器(已使用的免费浏览次数)。
该解决方案还允许发布商在 AMP 文档中放置一个登录链接,该链接会启动登录/订阅页面,发布商可以在其中对读者进行身份验证,并将读者的系统身份与 AMP 读者 ID 关联起来。
在基本形式中,此解决方案会将完整的(尽管模糊)文档发送给读者,并根据授权响应简单地显示/隐藏受限部分。但是,此解决方案还提供了“服务器”选项,其中受限部分可以从初始文档传递中排除,仅在授权得到确认后才下载。
支持 AMP 访问要求发布商实现上面描述的组件。需要访问内容标记和授权端点。Pingback 端点和登录页面是可选的。
AMP 阅读器 ID
为了协助访问服务和用例,AMP 访问引入了读者 ID的概念。
读者 ID 是 AMP 生态系统创建的匿名且唯一的 ID。对于每个读者/发布商对来说都是唯一的 - 读者对两个不同的发布商的识别方式不同。它是一个不可逆的 ID。读者 ID 包含在所有 AMP/发布商通信中,并且具有非常高的熵。发布商可以使用读者 ID 来识别读者,并将其映射到他们自己的身份系统。
读者 ID 在用户设备上构建,旨在长期存在。但是,它遵循正常的浏览器存储规则,包括隐身窗口的规则。读者 ID 的预期生命周期是两次使用之间为 1 年,或者直到用户清除其 Cookie。读者 ID 当前不会在设备之间共享。
读者 ID 的构建方式类似于构建 ExternalCID 的机制,该机制在此处进行了描述。一个示例读者 ID 为 amp-OFsqR4pPKynymPyMmplPNMvxSTsNQob3TnK-oE3nwVT0clORaZ1rkeEz8xej-vV6
。
AMP Access 和 Cookie
发布商可以使用他们自己的验证 Cookie,或者依赖于读者 ID,或者同时使用两者。
访问内容标记
访问内容标记根据从授权端点返回的授权响应确定哪些部分可见或隐藏。它通过特殊标记属性进行描述。
授权端点
授权是发布商提供的端点,由 AMP 运行时或 Google AMP 缓存调用。它是一个经过凭据认证的 CORS GET 端点。此端点返回可用于内容标记来隐藏或显示文档不同部分的访问参数。
Pingback 端点
Pingback 是发布商提供的端点,由 AMP 运行时或 Google AMP 缓存调用。它是一个经过凭据认证的 CORS POST 端点。当读者开始查看文档时,AMP 运行时会自动调用此端点。在读者成功完成登录流程后,也会调用此端点。Pingback 的主要目标之一是让发布商更新计量信息。
Pingback 是可选的。可以通过将 noPingback
配置属性设置为 true
来禁用它。
登录页面和登录链接
登录页面由发布商实现和提供,并由 AMP 运行时调用。它通常显示为浏览器对话框。
当读者点击登录链接时,会触发登录页面,该链接可以由发布商放置在文档中的任何位置。
规范 v0.1
配置
所有端点都以 JSON 对象的形式配置在文档的 HEAD 中的 AMP 文档中
<script id="amp-access" type="application/json"> { "property": value, ... } </script>
此配置中定义了以下属性
属性 | 值 | 描述 |
---|---|---|
authorization | <URL> | 授权端点的 HTTPS URL。 |
pingback | <URL> | Pingback 端点的 HTTPS URL。 |
noPingback | true/false | 为 true 时,禁用 pingback。 |
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 Access 配置示例
<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 Var 规范 中进行了定义。此外,此规范还添加了一些特定于访问的变量,例如 READER_ID
和 AUTHDATA
。下表中描述了一些最相关的变量
变量 | 描述 |
---|---|
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 Viewer 的 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-access
和 amp-access-hide
,它们可以放置在任何 HTML 元素上。
amp-access
属性提供了根据授权端点返回的授权响应产生真或假的表达式。结果值指示元素及其内容是否可见。
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>
此处
- 订阅者是授权端点返回的授权响应中的布尔字段。此部分默认情况下隐藏,这是可选的。
- 此示例选择以乐观方式显示全部内容。
以下是一个向读者显示计量状态的免责声明的示例
<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。除了 URL 参数之外,发布者还可以使用通过 HTTP 协议自然传递的任何信息,例如读者的 IP 地址。必须包含 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 运行时和扩展程序可以使用授权响应来实现三个不同的目的
- 在评估
amp-access
表达式时。 - 在评估
<template>
模板(例如amp-mustache
)时。 - 使用
AUTHDATA(field)
向 pingback 和登录 URL 提供其他变量时。
授权端点由 AMP 运行时作为已凭证 CORS 端点调用。因此,它必须实现 CORS 协议。它应使用 CORS 来源和源来源来限制对该服务的访问,如CORS 来源安全中所述。此端点可以使用发布者 cookie 来满足其需求。例如,它可以关联读者 ID 和发布者自己的用户身份之间的绑定。AMP 本身不需要了解这一点(并且更愿意不了解)。有关更多详细信息,请参阅AMP 读者 ID和AMP 访问和 Cookie文档。
AMP 运行时(或更确切地说,浏览器)在调用授权端点时会观察缓存响应标头。因此,可以重复使用缓存的响应。这可能不是理想的。如果不是理想的,发布者可以使用适当的缓存控制标头和/或端点 URL 的RANDOM
变量替换。
如果授权请求失败,AMP 运行时将回退到“authorizationFallbackResponse”,如果在配置中指定了它。在这种情况下,授权流将正常进行,授权响应的值为“authorizationFallbackResponse”属性。如果未指定“authorizationFallbackResponse”,则授权流将失败,在这种情况下,amp-access
表达式将不会被评估,并且部分是否可见或隐藏将由文档最初提供的amp-access-hide
属性的存在来决定。
授权请求将自动超时,并在 3 秒后假定已失败。
授权流程期间,AMP 运行时使用以下 CSS 类
- 授权流程开始时,
amp-access-loading
CSS 类被设置为文档根,并在流程完成或失败时移除。 - 授权流程失败时,
amp-access-error
CSS 类被设置为文档根。
在服务器选项中,Google AMP 缓存将授权端点调用作为一个简单的 HTTPS 端点进行。这意味着在这种情况下,发布商的 cookie 无法传递。
Pingback 端点
Pingback 通过 AMP Access 配置 部分中的 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 Access 配置 部分中的 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
替换,它将自动注入,其默认查询参数名称为“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 端点,以更新文档状态并使用新的访问配置文件报告“视图”。
登录链接
发布商可以选择将登录链接放置在文档内容中的任何位置。
通过 AMP Access 配置 部分中的“login”属性配置一个或多个登录 URL。
可以在允许“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 来源安全性
授权和 Pingback 端点是 CORS 端点,它们必须实现 AMP CORS 安全规范 中描述的安全协议。
计量
计量是读者在一段时间内免费查看多个文档视图的高级内容的系统。一旦达到某个配额,读者就会看到付费墙,而读者看到的则是带有追加销售信息和注册/登录链接的部分内容。例如,计量可以定义为“读者每月可以免费阅读 10 篇文章”。
AMP Access 提供以下用于实现计量访问的功能
- READER_ID 应用于存储计量信息。由于发布商无法始终依赖在第三方上下文中设置 Cookie,因此此数据应存储在服务器端。
- “阅读计数”只能在 Pingback 端点中更新。
- 只有唯一文档可以计入配额。即刷新同一文档十次构成单个视图。为此,授权和 Pingback 端点可以注入
SOURCE_URL
或类似的 URL 变量。请参阅 访问 URL 变量。
首次点击免费
Google 的首次点击免费 (或 FCF) 政策在此处 描述,此处 描述 了最近的更新详情。
要实施 FCF,发布者必须 (1) 能够确定每个视图的引用服务,以及 (2) 能够计算每个读者每天的视图数。
这两个步骤都包含在 AMP Access 规范中。引用者可以使用 DOCUMENT_REFERRER
URL 替换注入到授权和 Pingback URL 中,如 访问 URL 变量 中所述。视图计数可以使用服务器端的 Pingback 端点完成。这与 计量 中描述的计量实施非常相似。
登录流程
AMP 会以第一方窗口、弹出窗口或标签页的形式启动登录对话框。只要有可能,AMP 查看器都应尝试在浏览器上下文中启动登录对话框,以便它能够利用顶级浏览器 API。
当读者激活登录链接时,AMP 运行时会启动登录流程,从描述上来说,它遵循以下步骤
- AMP 运行时或查看器会针对指定的登录 URL 打开登录对话框(第一方窗口)。该 URL 包含一个额外的“返回 URL”URL 查询参数 (
&return=RETURN_URL
)。还可以将许多其他参数展开到 URL 中,例如读者 ID。有关更多详情,请参阅 登录页面 部分。 - 发布者显示一个自由格式的登录页面。
- 读者遵循登录步骤,例如输入用户名/密码或使用社交登录。
- 读者提交登录。发布者完成身份验证、设置 Cookie,最后将读者重定向到先前请求的“返回 URL”。重定向包含一个 URL 哈希参数
success
,它可以是true
或false
。 - 登录对话框遵循重定向到“返回 URL”。
- 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 年 9 月 2 日:“noPingback”配置属性和可选 pingback。
- 2016 年 3 月 3 日:登录后重新发送 pingback(v0.5)。
- 2016 年 2 月 19 日:更正示例以从 URL 变量替换中删除
{}
。 - 2016 年 2 月 15 日:配置 和 授权端点 现在允许使用“authorizationFallbackResponse”属性,该属性可在授权失败时使用。
- 2016 年 2 月 11 日:授权端点 中的授权请求超时。
- 2016 年 2 月 11 日:现在允许使用嵌套字段引用,例如
object.field
。 - 2016 年 2 月 9 日:首次点击免费 和 计量 部分。
- 2016 年 2 月 3 日:CORS 来源安全性 中添加了“来源来源”安全规范。
- 2016 年 2 月 1 日:可以使用 RETURN_URL URL 替换来自定义登录页面的“返回”查询参数。
附录 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