使用 Geolocation API 網路服務的最佳做法

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

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

什麼是網路服務?

您可以透過 Google 地圖平台網路服務,向外部服務要求 Maps API 資料,並在 Google 地圖應用程式中使用資料。依據《Google 地圖平台服務條款》中的授權限制規定,這些服務可與地圖搭配使用。

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

地理位置要求是使用 POST 傳送至下列網址:

https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_API_KEY

注意:所有 Geolocation 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 本身中處理。