使用 Street View Static API 的最佳做法

Google 地圖平台靜態 Web API 是 Google 服務的一組 HTTP 介面,這些介面會產生可直接嵌入網頁的圖片。

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

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

Street View Static API 的運作方式與靜態 Web API 類似,但中繼資料服務可視為網路服務。如要進一步瞭解中繼資料服務,請參閱「街景服務圖片中繼資料」一文。

什麼是 Static Web API?

Google 地圖平台靜態網路 API 可讓您在網頁中嵌入 Google 地圖圖片,完全無需 JavaScript 或任何動態頁面載入。靜態 Web API 會根據使用標準 HTTPS 要求傳送的網址參數,建立圖片。

常見的 Street View Static API 要求通常採用下列格式:

  https://www.googleapis.com/streetview/z/x/y?parameters

什麼是網路服務?

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

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

Street View Static API 中繼資料要求的格式如下:

https://maps.googleapis.com/maps/api/streetview/parameters

注意:所有 Street View Static API 應用程式都需要進行驗證。詳情請參閱驗證憑證

SSL/TLS 存取

所有使用 API 金鑰或包含使用者資料的 Google 地圖平台要求,都必須採用 HTTPS。透過 HTTP 發出的包含機密資料的要求可能會遭到拒絕。

建立有效網址

您可能認為網址是否「有效」一眼就能判斷,但實際情況不然。例如,在瀏覽器的網址列內輸入的網址可能包含特殊字元 (例如 "上海+中國");瀏覽器必須在內部將這些字元轉譯為其他編碼方式才能傳送。同理可證,產生或接受 UTF-8 輸入值的任何程式碼都可能會將含有 UTF-8 字元的網址視為「有效網址」,但也需要先轉譯這些字元,才能向外傳送至網路伺服器。這個過程稱為網址編碼百分比編碼

特殊字元

所有網址都必須符合統一資源 ID (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 文字字串、結構用途 (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 地圖平台網路服務和 Static Web API 的網址長度上限都是 16384 個字元。對於大部分的服務而言,很少出現接近此字元限制的情況。但請注意,某些服務的幾個參數可能會產生較長的網址。

友善使用 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 本身中處理。