透過 Remote API 存取 App Engine

區域 ID

REGION_ID 是 Google 根據您在建立應用程式時選取的地區所指派的簡寫代碼。雖然某些區域 ID 可能看起來與常用的國家/地區代碼相似,但此代碼並非對應國家/地區或省份。如果是 2020 年 2 月後建立的應用程式,App Engine 網址會包含 REGION_ID.r。如果是在此日期之前建立的現有應用程式,網址中則可選擇加入地區 ID。

進一步瞭解區域 ID

所有 Python 用戶端都可透過 Remote API 程式庫存取 App Engine 應用程式的可用服務。

舉例來說,如果您的 App Engine 應用程式使用 Datastore 或 Google Cloud Storage,Python 用戶端就能使用遠端 API 存取這些儲存空間資源。

若要存取應用程式的資料儲存庫,您可以透過 Remote API 從本機機器上執行的應用程式或從本機互動式 Remote API 殼層來執行存取作業。Remote API 會與實際服務互動,因此存取作業會用到配額與計費資源。

啟用應用程式的 Remote API 存取

為應用程式啟用遠端 API 最簡單的方式,就是在應用程式的 app.yaml 檔案中使用 builtins 指令,該指令會指定預設網址 /_ah/remote_api/。不過,您可以改用同一個檔案中的 url 指示詞,指定其他網址。

builtin

app.yaml 檔案中的 builtins 指示詞會在預設網址 /_ah/remote_api 中提供遠端 API:

runtime: python27
api_version: 1
threadsafe: true

builtins:
- remote_api: on

URL

您可以使用 app.yaml 中的 url 指示詞,指定要與遠端 API 搭配使用的不同網址:

- url: /some-URL/*
  script: google.appengine.ext.remote_api.handler.application

進行這項變更後,請務必將應用程式部署至 App Engine。

使用 Remote API 殼層

Python SDK 包含 Remote API 殼層,可讓您在應用程式使用的 App Engine 服務上叫用 Python 指令。您無需額外提供任何驗證,因為這會自動使用您將應用程式上傳至 App Engine 時的相同憑證。

如要啟動 Remote API 殼層:

  1. 從本機電腦中的終端機視窗叫用下列指令:

    SDK-INSTALL-DIRECTORY/remote_api_shell.py -s YOUR-PROJECT-ID. REGION_ID.r.appspot.com

    [SDK-INSTALL-DIRECTORY] 替換為 Python 專用 App Engine SDK 的路徑,並將 [YOUR-PROJECT-ID] 替換為您的專案 ID。

  2. 在接著顯示的互動式殼層中,叫用您要執行的 Python 指令。舉例來說,如果應用程式使用 Datastore,您可以叫用下列 NDB 查詢來擷取 10 筆記錄:

     >>> from google.appengine.ext import ndb
     >>>
     >>> # Fetch 10 keys from the datastore
     >>> ndb.Query().fetch(10, keys_only=True)
    

在本機用戶端上使用 Remote API

您也可以在本機應用程式中使用 Remote API,以便存取在 App Engine 中執行的應用程式所使用的服務。

如要在本機應用程式上使用 Remote API:

  1. 啟用 Remote API

  2. 匯出 Python 目錄中的 PYTHONPATH 環境變數,例如:

     export PYTHONPATH=/usr/somedir/v3/bin/python2.7
    

    以實際的 Python 位置值取代該路徑。

  3. 將 Python 專用的 App Engine SDK 的位置新增至 PYTHONPATH

     export GAE_SDK_ROOT="/usr/local/home/mydir/google_appengine"
     export PYTHONPATH=${GAE_SDK_ROOT}:${PYTHONPATH}
    

    以 App Engine SDK 的實際路徑取代上方的 SDK 路徑。

  4. 在用戶端程式碼中匯入 dev_appserver 並呼叫 dev_appserver.fix_sys_path(),確保所有的 App Engine SDK 模組均已正確匯入:

    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
  5. 將下列 remote_api_stub 程式碼新增至應用程式,並確認在程式碼中傳送專案 ID:

    remote_api_stub.ConfigureRemoteApiForOAuth(
        '{}.appspot.com'.format(project_id),
        '/_ah/remote_api')

    如果您未為 Remote API 使用預設網址 /_ah/remote_api,就必須變更上述程式碼,以反映您使用的網址。如需 remote_api_stub.ConfigureRemoteApiForOAuth 的定義和說明文件,請參閱 SDK 檔案 [SDK-INSTALL-DIRECTORY]/google/appengine/ext/remote_api/remote_api_stub.py

  6. 新增任何必要 App Engine 匯入項目和 Python 程式碼,以便使用所需的 App Engine 服務。執行以下程式碼範例,即可存取專案的資料儲存庫:

    
    import argparse
    
    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
    except ImportError:
        print('Please make sure the App Engine SDK is in your PYTHONPATH.')
        raise
    
    from google.appengine.ext import ndb
    from google.appengine.ext.remote_api import remote_api_stub
    
    
    def main(project_id):
        remote_api_stub.ConfigureRemoteApiForOAuth(
            '{}.appspot.com'.format(project_id),
            '/_ah/remote_api')
    
        # List the first 10 keys in the datastore.
        keys = ndb.Query().fetch(10, keys_only=True)
    
        for key in keys:
            print(key)
    
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(
            description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter)
        parser.add_argument('project_id', help='Your Project ID.')
    
        args = parser.parse_args()
    
        main(args.project_id)
  7. 在應用程式部署至 App Engine 的情況下,啟動 Remote API 用戶端:

     python your-client.py YOUR-PROJECT-ID
    

    your-client.py 替換為您的用戶端模組,並將 YOUR-PROJECT-ID 替換為您的專案 ID。這項操作是假設您的用戶端會按照 client.py 程式碼範例接受指令列輸入內容中的專案 ID。

限制與最佳做法

remote_api 模組會盡所有可能,使其運作方式與原生 App Engine 資料儲存庫完全相同。在某些情況下,這意謂著該運作效率可能會較原有運作方式低。使用 remote_api 時,必須記住幾個重點:

每個資料儲存庫要求都需要一去一回

由於您是透過 HTTP 存取資料儲存庫,因此產生的負擔與延遲會比本機存取略高一些。為加快速度並減少負荷,請透過批次取得與放入,以及批次從查詢擷取實體,嘗試限制去回的次數。無論是對於 remote_api,還是在一般情況下使用資料儲存庫,這都是值得參考的建議,因為系統只會將批次作業視為單一資料儲存庫作業。例來說,如果您不想這樣做:

for key in keys:
  rec = key.get()
  rec.foo = bar
  rec.put()

可以改為執行:

records = ndb.get_multi(keys)
for rec in records:
  rec.foo = bar
  ndb.put_multi(records)

這兩個範例的效果相同,但後者總共只需要兩次去回,前者的每個實體則都需要兩次去回。

向 remote_api 發出的要求會使用配額

由於 remote_api 透過 HTTP 操作,因此您每次呼叫資料儲存庫都會針對 HTTP 要求產生配額使用量、接收和傳送的位元組,以及您預期的一般資料儲存庫配額。如果您是透過 remote_api 執行批次更新,請務必記住這一點。

適用 1 MB API 限制

跟在本機執行時一樣,API 要求和回應的 1MB 限制仍然適用。如果您的實體數量特別龐大,您可能需要限制一次擷取或放入的數量,以符合這個限制。不幸的是,這會與去回次數的最小化發生衝突,因此最好的做法是,使用不超過要求或回應限制的最大批次操作數量。但是,就大多數的實體來說,這不會是一個問題。

避免疊代處理查詢

以下是一個常見的資料儲存庫存取模式:

q = MyModel.query()
for entity in q:
  # Do something with entity

如果您採用這個模式,SDK 會以 20 個實體為一個批次的方式從資料儲存庫中擷取實體,並在現有實體耗盡時擷取新的一批實體。remote_api 必須透過不同的要求擷取各批實體,因此效率較低。有鑑於此,remote_api 會改用偏移功能進一步擷取結果,為每個批次執行全新的查詢。

如果您可以掌握所需實體數量,則能直接在單次要求中擷取所需數量來完成整項擷取工作。

entities = MyModel.query().fetch(100)
for entity in entities:
  # Do something with entity

如果您無法掌握所需實體數量,可以使用游標有效率地疊代處理大型結果集。這也可以讓您規避一般資料儲存庫查詢的 1000 個實體限制。

交易的效率較低

為了透過 remote_api 實作交易,將累積在交易內部擷取的實體資訊,以及在交易內部放置或刪除的實體副本。認可交易之後,系統會將這些資訊全數傳送至 App Engine 伺服器,而其必須在此處再次擷取交易所使用的所有實體、確認這些實體未遭到修改,然後放入並刪除交易所做的所有變更,再予以認可。如果發生衝突,伺服器會退回交易,並通知用戶端,然後用戶端必須重複整個過程。

這個方法是行得通的,而且會在本機資料儲存庫上完整重現交易所提供的功能,不過效率較低。總而言之,您可以在需要時使用交易,但是為求效率,請嘗試限制您執行的交易數量與複雜性。