Google Maps Platform 静态 Web API 是一组 HTTP 接口,可生成直接嵌入到网页中的图片。
Google Maps Platform 网络服务是一组 HTTP 接口,可为您的地图应用提供地理数据。
本指南介绍了一些有助于设置图片和 Web 服务请求以及处理服务响应的常见做法。如需详细了解 Street View Static API,请参阅开发者指南。
街景 Static API 的作用类似于静态 Web API,而元数据服务的作用类似于 Web 服务。如需详细了解元数据服务,请参阅街景图片元数据。
什么是静态 Web API?
借助 Google Maps Platform 静态 Web API,您可以在网页中嵌入 Google 地图图片,而无需使用 JavaScript 或任何动态网页加载。静态 Web API 会根据使用标准 HTTPS 请求发送的网址参数创建图片。
典型的 Street View Static API 请求具有以下形式:
https://www.googleapis.com/streetview/z/x/y?parameters
什么是 Web 服务?
Google Maps Platform Web 服务是一种接口,用于从外部服务请求地图 API 数据,并在您的地图应用中使用这些数据。根据 Google Maps Platform 服务条款中的许可限制,这些服务旨在与地图结合使用。
Maps API Web 服务使用 HTTP 或 HTTPS 请求向特定网址传递网址参数或 JSON 格式的 POST 数据作为服务实参。一般来说,这些服务会在响应正文中以 JSON 格式返回数据,供您的应用解析或处理。
Street View Static API 元数据请求采用以下形式:
https://maps.googleapis.com/maps/api/streetview/parameters
SSL 和 TLS 访问权限
对于使用 API 密钥或包含用户数据的所有 Google Maps Platform 请求,必须采用 HTTPS 协议。通过 HTTP 发送的包含敏感数据的请求可能会被拒绝。
构建有效网址
您可能认为“有效”网址不言自明,但实际并非如此。例如,在浏览器地址栏中输入的网址可能包含特殊字符(例如 "上海+中國");浏览器需要先在内部将这些字符转换为其他编码,然后再进行传输。同样,任何生成或接受 UTF-8 输入的代码都可能会将包含 UTF-8 字符的网址视为“有效”,但同样需要先转换这些字符,然后再将其发送给网络服务器。该过程称为网址编码或百分号编码。
特殊字符
我们之所以需要转换特殊字符,是因为所有网址都需要符合统一资源标识符 (URI) 规范所规定的语法。实际上,这意味着网址必须只包含一个特殊的 ASCII 字符子集:大家熟悉的字母数字符号以及一些在网址内用作控制字符的预留字符。下表汇总了这些字符:
| 字符集 | 字符 | 在网址中的用法 |
|---|---|---|
| 字母数字 | a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 | 文本字符串、在 scheme 中使用 (http)、端口 (8080) 等 |
| 非预留字符 | - _ . ~ | 文本字符串 |
| 预留字符 | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | 控制字符和/或文本字符串 |
构建有效网址时,您必须确保网址只包含表格中显示的那些字符。让网址按照上述字符集使用字符通常会带来两个问题,一个是遗漏问题,一个是替换问题:
- 您要处理的字符未包含在上述字符集内。举例来说,非英语字符(例如
上海+中國)需要使用上述字符进行编码。按照常见惯例,空格(网址内不允许使用空格)通常也使用加号字符'+'表示。 - 字符在上述字符集内存在且属于预留字符,但需要按原义使用。例如,
?在网址内用于表示查询字符串的开头;如果您想要使用字符串“? and the Mysterions”,则需要对'?'字符进行编码。
所有要进行网址编码的字符都会使用一个 '%' 字符和一个与其 UTF-8 字符对应的双字符十六进制值进行编码。例如,UTF-8 中的 上海+中國 在进行网址编码后将变为 %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B。字符串 ? and the Mysterians 在进行网址编码后将变为 %3F+and+the+Mysterians 或 %3F%20and%20the%20Mysterians。
需要编码的常见字符
以下是一些必须进行编码的常见字符:
| 不安全的字符 | 编码后的值 |
|---|---|
| 空格 | %20 |
| " | %22 |
| < | %3C |
| > | %3E |
| # | %23 |
| % | %25 |
| | | %7C |
转换您通过用户输入获取的网址有时颇为棘手。例如,用户可能会输入“5th&Main St.”这样的地址。一般而言,您应该根据网址的组成部分来构建网址,将所有用户输入都视为原义字符。
此外,对于所有的 Google Maps Platform 网络服务 API 或静态网络 API,网址最多可包含 16384 个字符。对于大多数服务,很少出现接近这一字符数限制的情况。但请注意,某些服务具有的若干参数可能会导致网址较长。
礼貌地使用 Google API
设计不当的 API 客户端可能会给互联网和服务器带来沉重的负担。本部分包含 API 客户端的最佳实践。遵循这些最佳实践有助于防止您的应用因意外滥用 API 而遭到屏蔽。
指数退避算法
在极少数情况下,您的请求可能会出现问题;您可能会收到 4xx 或 5xx HTTP 响应代码,或者 TCP 连接可能会在您的客户端与 Google 的服务器之间的某个位置失败。通常,值得重试请求,因为后续请求可能会在原始请求失败时成功。 不过,请务必不要反复向 Google 的服务器发出请求。这种循环行为可能会使客户端与 Google 之间的网络过载,从而导致许多方出现问题。
更好的方法是重试,并在每次尝试之间增加延迟时间。延迟时间通常会在每次尝试时按一个乘法系数增加,这种方法称为指数退避算法。
例如,假设某个应用向 Time Zone API 发出以下请求:
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEY以下 Python 示例展示了如何使用指数退避机制发出请求:
import json import time import urllib.error import urllib.parse import urllib.request # The maps_key defined in the following code isn't a valid Google Maps API key. # You need to get your own API key. # See https://developers.google.com/maps/documentation/timezone/get-api-key API_KEY = "YOUR_KEY_HERE" TIMEZONE_BASE_URL = "https://maps.googleapis.com/maps/api/timezone/json" def timezone(lat, lng, timestamp): # Join the parts of the URL together into one string. params = urllib.parse.urlencode( {"location": f"{lat},{lng}", "timestamp": timestamp, "key": API_KEY,} ) url = f"{TIMEZONE_BASE_URL}?{params}" current_delay = 0.1 # Set the initial retry delay to 100ms. max_delay = 5 # Set the maximum retry delay to 5 seconds. while True: try: # Get the API response. response = urllib.request.urlopen(url) except urllib.error.URLError: pass # Fall through to the retry loop. else: # If the request didn't produce an IOError, parse the result. result = json.load(response) if result["status"] == "OK": return result["timeZoneId"] elif result["status"] != "UNKNOWN_ERROR": # Many API errors can't be fixed by a retry, such as # INVALID_REQUEST or ZERO_RESULTS. Don't retry these requests. raise Exception(result["error_message"]) if current_delay > max_delay: raise Exception("Too many retry attempts.") print("Waiting", current_delay, "seconds before retrying.") time.sleep(current_delay) current_delay *= 2 # Increase the delay on each retry. if __name__ == "__main__": tz = timezone(39.6034810, -119.6822510, 1331161200) print(f"Timezone: {tz}")
确保应用调用链中没有会导致快速连续重复请求的重试代码。
同步请求
大量同步请求发送到 Google 的 API 可能会被视为对 Google 基础设施的分布式拒绝服务 (DDoS) 攻击,并会相应地进行处理。为避免此问题,请确保 API 请求在客户端之间不同步。
例如,假设某个应用用于显示当前时区的时间。此应用可能在客户端操作系统中设置了一个闹钟,以便在每分钟开始时唤醒它,从而更新显示的时间。 请勿在应用中进行任何 API 调用,作为与该闹钟关联的处理的一部分。
响应固定闹钟而发出 API 调用是不好的做法,因为这会导致 API 调用与分钟的开始时间同步,即使在不同的设备之间也是如此,而不是随时间均匀分布。如果应用设计不当,这样做会在每分钟开始时生成比正常水平高 60 倍的流量高峰。
不过,您可以将应用设计为设置第二个闹钟,该闹钟会在随机选择的时间响起。当第二个闹钟触发时,应用会调用所需的任何 API 并存储结果。当应用在每分钟开始时更新其显示内容时,它会使用之前存储的结果,而不是再次调用 API。采用此方法,API 调用会均匀分布在一段时间内。 此外,当显示屏更新时,API 调用不会延迟渲染。
除了每分钟的开始时间之外,请勿以其他常见的同步时间为目标,例如每小时的开始时间和每天午夜的开始时间。
处理响应
由于对 Web 服务请求的各个响应的确切格式无法保证(某些元素可能缺失或位于多个位置),因此请勿假设针对任何给定响应返回的格式对于不同的查询都是相同的。而是使用表达式处理响应并选择适当的值。
本部分讨论了如何从 Web 服务响应中动态提取这些值。
Google 地图网络服务提供的响应可以理解,但不够人性化。执行查询时,您可能不是要显示一组数据,而是要提取一些特定值。通常,解析来自 Web 服务的响应,并仅提取您感兴趣的值。
您使用的解析方案取决于是否以 JSON 格式返回输出。 JSON 响应本身就是 JavaScript 对象,因此可以在客户端上使用 JavaScript 本身进行处理。