使用地圖圖塊 API 網路服務的最佳做法

Google 地圖平台網路服務是一組 HTTP 介面,可連結 Google 服務,為地圖應用程式提供地理資料。

本指南說明一些常見做法,有助於設定網路服務要求及處理服務回應。如需 Map Tiles API 的完整說明文件,請參閱開發人員指南。

什麼是網路服務?

Google Maps Platform Web 服務提供介面,可向外部服務要求 Maps API 資料,並在 Maps 應用程式中使用。根據《Google 地圖平台服務條款》的授權限制,這些服務應與地圖搭配使用。

Maps API Web 服務會使用 HTTP(S) 要求,將網址參數和/或 JSON 格式的 POST 資料,當做引數傳遞至特定網址。一般來說,這些服務會在回應主體中以 JSON 格式傳回資料,供應用程式剖析和/或處理。

街景服務中繼資料要求就是一種網路服務要求,格式如下:

https://tile.googleapis.com/v1/streetview/metadata?session=YOUR_SESSION_TOKEN&key=YOUR_API_KEY&panoId=panoId

注意:所有 Map Tiles API 應用程式都必須經過驗證。進一步瞭解驗證憑證。

SSL/TLS 存取權

凡是使用 API 金鑰或包含使用者資料的 Google 地圖平台要求,都必須透過 HTTPS 傳送。如果透過 HTTP 提出的要求含有機密資料,可能會遭到拒絕。

合理使用 Google API

設計不良的 API 用戶端可能會對網際網路和 Google 伺服器造成不必要的負載。本節提供一些 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&timestamp=1331161200&key=YOUR_API_KEY

以下 Python 範例說明如何使用指數輪詢提出要求:

import json
import time
import urllib.error
import urllib.parse
import urllib.request

# The maps_key defined below 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 we didn't get an IOError then parse the result.
            result = json.load(response)

            if result["status"] == "OK":
                return result["timeZoneId"]
            elif result["status"] != "UNKNOWN_ERROR":
                # Many API errors cannot be fixed by a retry, e.g. INVALID_REQUEST or
                # ZERO_RESULTS. There is no point retrying 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 each time we retry.


if __name__ == "__main__":
    tz = timezone(39.6034810, -119.6822510, 1331161200)
    print(f"Timezone: {tz}")

此外,請務必確認應用程式呼叫鏈中沒有較高的重試程式碼,以免在短時間內連續傳送重複要求。

同步要求

如果同時向 Google API 發出大量同步要求,可能會被視為對 Google 基礎架構發動分散式阻斷服務 (DDoS) 攻擊,並受到相應處置。為避免這種情況,請確保 API 要求不會在用戶端之間同步處理。

舉例來說,假設某個應用程式會顯示目前時區的時間。這個應用程式可能會在用戶端作業系統中設定鬧鐘,在每分鐘開始時喚醒作業系統,以便更新顯示的時間。應用程式不應發出任何 API 呼叫,做為與該鬧鐘相關聯的處理作業。

在回應固定鬧鐘時發出 API 呼叫並非理想做法,因為這會導致 API 呼叫同步至分鐘的開頭,甚至在不同裝置之間也是如此,而不是隨著時間平均分配。如果應用程式設計不佳,就會在每分鐘開始時產生高達正常水準六十倍的流量。

相反地,一個可能的好設計是將第二個鬧鐘設定為隨機選擇的時間。當第二個鬧鐘響起時,應用程式會呼叫所需的任何 API 並儲存結果。當應用程式想在每分鐘開始時更新顯示內容,就會使用先前儲存的結果,而不是再次呼叫 API。這樣一來,API 呼叫就會平均分散在一段時間內。此外,更新螢幕時,API 呼叫不會延遲算繪。

除了每分鐘開始時,其他應避免同步處理的常見時間包括每小時開始時,以及每天午夜開始時。

處理回應

本章節討論如何從網路服務回應中,以動態方式擷取這些值。

Google 地圖網路服務提供的回應容易理解,但對使用者來說不夠友善。執行查詢時,您可能想擷取幾個特定值,而不是顯示一組資料。一般來說,您會想要剖析網路服務的回應,並只擷取您感興趣的值。

剖析配置取決於是否以 JSON 格式傳回輸出內容。JSON 回應本身就是 JavaScript 物件,因此可在用戶端上直接透過 JavaScript 處理。