本文介绍了一些您可以用来提高应用性能的技术。在某些情况下,我们会使用其他 API 或通用 API 中的示例来解释所给出的观点。不过,其中的概念对于 Google Analytics(分析)API 也同样适用。
使用 gzip
要降低单个请求的带宽需求,您可以选择启用 gzip 压缩,这是一种既方便又简单的方法。虽然这种方法需要一些额外的 CPU 时间对结果进行解压缩,但考虑到它对节约网络费用的贡献,通常还是值得一用的。
要接收 gzip 编码的响应,您必须执行以下两项操作:设置 Accept-Encoding
标头,并且修改您的用户代理以包含字符串 gzip
。下面提供了一个用于启用 gzip 压缩的格式正确的 HTTP 标头示例:
Accept-Encoding: gzip User-Agent: my program (gzip)
处理部分资源
提高 API 调用性能的另一方法是仅发送和接收您感兴趣的那部分数据。这样可使您的应用避免传输、解析和存储不需要的字段,以便其可以更有效地使用包括网络、CPU 和内存在内的资源。
部分请求有以下两种类型:
有关发送部分请求的详情,请参阅以下部分。
部分响应
默认情况下,服务器在处理请求之后会发回资源的完整表述。为实现最佳性能,您可以要求服务器仅发送您真正需要的字段,并且接收部分响应。
要请求部分响应,请使用 fields
请求参数来指定您希望返回的字段。您可以将该参数与返回响应数据的任何请求配合使用。
请注意,fields
参数仅影响响应数据;它不会影响您需要发送的数据(如果有)。要减少您在修改资源时所发送的数据量,请使用补丁请求。
示例
以下示例显示的是 fields
参数与常规(虚构)“Demo”API 配合使用的情况。
简单请求:下面的HTTP GET
请求省略了fields
参数,因而会返回完整资源。
https://www.googleapis.com/demo/v1?key=YOUR-API-KEY
完整资源响应:完整资源数据包括以下字段以及其他许多字段(为简便起见,此处省略了那些字段)。
{ "kind": "demo", ... "items": [ { "title": "First title", "comment": "First comment.", "characteristics": { "length": "short", "accuracy": "high", "followers": ["Jo", "Will"], }, "status": "active", ... }, { "title": "Second title", "comment": "Second comment.", "characteristics": { "length": "long", "accuracy": "medium" "followers": [ ], }, "status": "pending", ... }, ... ] }
部分响应请求:同样针对这项资源的以下请求使用了fields
参数,大大减少了所返回的数据量。
https://www.googleapis.com/demo/v1?key=YOUR-API-KEY&fields=kind,items(title,characteristics/length)
部分响应:服务器为响应上述请求而发回的响应只包含类型信息和一个简化的 items 数组,该数组中的每个项目只包含 HTML 标题和长度特征信息。
200 OK { "kind": "demo", "items": [ { "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ]
请注意,该响应是一个只包括所选字段及其所属父对象的 JSON 对象。
下面将首先讲述有关 fields
参数格式的详情,然后会详细介绍响应中所返回的确切对象。
Fields 参数语法概述
fields
请求参数值的格式大致上基于 XPath 语法。支持的语法总结如下,另外下一节还将提供更多示例。
- 使用以逗号分隔的列表来选择多个字段。
- 使用
a/b
选择嵌套在字段a
内的字段b
;使用a/b/c
选择嵌套在b
内的字段c
。
例外情况:在使用“data”封装容器的 API 响应中(响应嵌套在
data
对象内,例如data: { ... }
),不要在fields
规范内包含“data
”。在 fields 规范中加入类似data/a/b
的 data 对象会引发错误。所以,应该使用a/b
形式的fields
规范。 - 通过将表达式放在圆括号“
( )
”内,使用子选择器请求数组或对象的一组特定子字段。例如:
fields=items(id,author/email)
只会返回 items 数组中每个元素的项目 ID 和作者的电子邮件。您也可以指定单个子字段,这种情况下fields=items(id)
等同于fields=items/id
。 - 如果需要,可在选择字段时使用通配符。
例如:使用
fields=items/pagemap/*
可选择 pagemap 中的所有对象。
有关使用 fields 参数的更多示例
以下示例包含关于 fields
参数值如何影响响应的说明。
注意:与所有查询参数值一样,fields
参数值也必须经过网址编码。为了便于阅读,本文中的示例省略了编码。
- 指定您想返回的字段,或者进行字段选择。
fields
请求参数值是以逗号分隔的字段列表,并且每个字段是根据响应的根指定的。因此,如果您执行的是 list 操作,则响应是一个集合,并且通常包含一组资源。如果您执行的是返回单一资源的操作,则字段是根据该资源来指定。如果您选择的字段是(或属于)一个数组,则服务器会返回数组中所有元素的选定部分。
以下是一些集合级别的示例:
示例 结果 items
返回 items 数组中的所有元素,包括每个元素中的所有字段,但不包括其他字段。 etag,items
同时返回 etag
字段和 items 数组中的所有元素。items/title
仅返回 items 数组中所有元素的 title
字段。
每当返回嵌套字段时,响应中均包括该字段的父对象。父级字段不会包括其他任何子字段(除非已明确选择)。context/facets/label
仅返回 facets
数组中所有元素的label
字段,而该数组本身嵌套在context
对象之下。items/pagemap/*/title
对于 items 数组中的每个元素,仅返回 pagemap
的所有子对象的title
字段(如果存在)。
以下是一些资源级别的示例:
示例 结果 title
返回所请求资源的 title
字段。author/uri
返回所请求资源中 author
对象的uri
子字段。links/*/href
返回 links
的所有子对象的href
字段。- 使用“子选择”仅请求特定字段的相关部分。
- 默认情况下,如果您的请求指定具体字段,则服务器会返回全部对象或数组元素。您可以指定一个仅包含某些子字段的响应。如下所示,您可以使用“
( )
”子选择语法实现此目标。示例 结果 items(title,author/uri)
仅返回 items 数组中每个元素的 title
和作者uri
的值。
处理部分响应
服务器处理完包含 fields
查询参数的有效请求之后,会发回 HTTP 200 OK
状态代码以及所请求的数据。如果 fields
查询参数出现错误或因其他原因而无效,服务器将返回 HTTP 400 Bad Request
状态代码以及一条错误消息,告知用户他们的字段选择出现了什么错误(例如 "Invalid field selection a/b"
)。
以下是上文简介部分所提到的部分响应的示例。该请求使用 fields
参数来指定要返回的字段。
https://www.googleapis.com/demo/v1?key=YOUR-API-KEY&fields=kind,items(title,characteristics/length)
部分响应如下所示:
200 OK { "kind": "demo", "items": [ { "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ]
注意:对于支持数据分页查询参数(例如 maxResults
和 nextPageToken
)的 API,请使用这些参数将每个查询的结果减少到便于管理的数量。否则,可能无法实现本应通过部分响应获得的性能提升。
补丁(部分更新)
您还可以在修改资源时避免发送不必要的数据。如果仅为您要更改的具体字段发送更新数据,请使用 HTTP PATCH
动词。本文档所述的补丁语义不同于针对部分更新旧版 GData 实施的补丁语义(并且较之更简单)。
下面的简短示例显示了如何使用补丁减少您为进行小部分更新而需发送的数据。
示例
本例显示的是一个简单补丁请求,用于仅更新一个名为“Demo”的常规(虚构的)API 资源的标题。该资源还包含一条注释、一组特征、状态以及许多其他字段,但是该请求仅会发送 title
字段(因为这是唯一经过修改的字段):
PATCH https://www.googleapis.com/demo/v1/324 Authorization: Bearer your_auth_token Content-Type: application/json { "title": "New title" }
响应:
200 OK { "title": "New title", "comment": "First comment.", "characteristics": { "length": "short", "accuracy": "high", "followers": ["Jo", "Will"], }, "status": "active", ... }
服务器将返回 200 OK
状态代码以及已更新资源的完整表述。由于补丁请求中仅包含 title
字段,因此只有该值会与之前的有所不同。
注意:如果您将部分响应 fields
参数与补丁配合使用,则可以进一步提高更新请求的效率。补丁请求只会减少请求的大小,部分响应则会减少响应的大小。因此,要同时从这两个方向减少数据发送量,请结合使用补丁请求与 fields
参数。
补丁请求的语义
补丁请求的正文仅包含您要修改的资源字段。指定字段时,您必须包含任何外围父对象,因为外围父对象会与部分响应一起返回。您发送的已修改数据将合并到父对象(如果有)的数据中。
- 添加:要添加目前并不存在的字段,请指定这个新字段及其值。
- 修改:要更改现有字段的值,请指定该字段并为其设置新值。
- 删除:要删除字段,请指定相应字段并将其设为
null
。示例:"comment": null
。您还可以删除整个对象(如果它是可变的),只需将其设为null
即可。如果您要使用 Java API 客户端库,请改用Data.NULL_STRING
;有关详情,请参见 JSON null。
数组备注:包含数组的补丁请求将使用您提供的数组替换现有数组。您无法在数组中逐个修改、添加或删除项目。
在读取-修改-写入周期中使用补丁
一种比较实用的做法是,先提取包含您要修改的数据的部分响应。这对于使用 ETag 的资源来说尤为重要,因为您必须在 If-Match
HTTP 标头中提供当前的 ETag 值,以便成功更新资源。获取数据之后,您就可以修改自己想要更改的任何值,并且将已修改的部分表述与补丁请求一起发回。以下示例假设 Demo 资源使用 ETag:
GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics Authorization: Bearer your_auth_token
以下是部分响应:
200 OK { "etag": "ETagString" "title": "New title" "comment": "First comment.", "characteristics": { "length": "short", "level": "5", "followers": ["Jo", "Will"], } }
以下补丁请求基于该响应。如下所示,该请求还使用 fields
参数对补丁响应中返回的数据进行限制:
PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics Authorization: Bearer your_auth_token Content-Type: application/json If-Match: "ETagString" { "etag": "ETagString" "title": "", /* Clear the value of the title by setting it to the empty string. */ "comment": null, /* Delete the comment by replacing its value with null. */ "characteristics": { "length": "short", "level": "10", /* Modify the level value. */ "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */ "accuracy": "high" /* Add a new characteristic. */ }, }
服务器将返回 200 OK HTTP 状态代码,以及已更新资源的部分表述:
200 OK { "etag": "newETagString" "title": "", /* Title is cleared; deleted comment field is missing. */ "characteristics": { "length": "short", "level": "10", /* Value is updated.*/ "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */ "accuracy": "high" /* New characteristic is present. */ } }
直接构建补丁请求
对于某些补丁请求,您需要以您先前提取的数据为基础。例如,如果您希望向数组中添加项目,并且不希望丢失任何现有的数组元素,则需要首先获取现有的数据。同样,如果 API 使用 ETag,您需要将之前的 ETag 值与您的请求一起发送,以便成功更新资源。
注意:您可以使用 "If-Match: *"
HTTP 标头在使用 ETag 时强制完成补丁。如果您执行了以上操作,就无需在写入之前执行读取操作。
然而,在其他一些情况下,您可以直接构建补丁请求,无需首先提取现有数据。例如,您可以轻松创建补丁请求,将字段更新为新值或添加新字段。示例如下:
PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics Authorization: Bearer your_auth_token Content-Type: application/json { "comment": "A new comment", "characteristics": { "volume": "loud", "accuracy": null } }
对于该请求,如果 comment 字段有个现有值,则新值会覆盖该值;否则,系统会将该字段设置为新值。同样,如果有音量特征,则该值会被覆盖;如果没有,则会新建一个。accuracy 字段(如果已设置)会被删除。
处理补丁响应
处理完有效补丁请求之后,API 将返回 200 OK
HTTP 响应代码以及已修改资源的完整表述。如果 API 使用 ETag,服务器会像处理 PUT
一样,在成功处理了补丁请求后更新 ETag 值。
除非您使用了 fields
参数来减少补丁请求所返回的数据量,否则该请求将返回完整资源表述。
如果某个补丁请求导致新的资源状态在语法或语义上无效,服务器将返回 400 Bad Request
或 422 Unprocessable Entity
HTTP 状态代码,同时资源状态保持不变。例如,如果您尝试删除必填字段的值,服务器就会返回错误。
PATCH HTTP 不受支持时的替代符号
如果您的防火墙不允许 HTTP PATCH
请求,请执行 HTTP POST
请求并且将替代标头设为 PATCH
,如下所示:
POST https://www.googleapis.com/... X-HTTP-Method-Override: PATCH ...
补丁与更新之间的区别
实际上,在为使用了 HTTP PUT
动词的更新请求发送数据时,您只需发送相应的必需或可选字段;如果您发送服务器所设置的字段值,这些值将会被忽略。尽管该方法看起来好像是执行部分更新的另一方法,但有一些缺陷。对于使用 HTTP PUT
动词的更新,如果您没有提供必需参数,则请求会失败;同样,如果您没有提供可选参数,则请求会清除之前设置的数据。
出于以上原因考虑,使用补丁是更安全的选择。您只需为自己想要修改的字段提供数据;系统不会清除您忽略的字段。此规则唯一的例外与重复的元素或数组有关:如果您忽略所有重复的元素或数组,它们将会保持原样;如果您提供其中的任意元素或数组,系统将会使用您提供的元素或数组来代替全部元素或数组。