https.onCall 的通訊協定規格

Cloud Functions 的 https.onCall 觸發條件是 HTTPS 觸發條件,要求和回應的格式必須符合特定規定。本節提供用戶端 SDK 用來實作 API 的 HTTPS 要求和回應格式規格。如果 Android、Apple 平台或網頁 SDK 無法滿足您的需求,這項資訊或許能派上用場。

要求格式:標頭

對可呼叫觸發端點發出的 HTTP 要求必須是 POST,並包含下列標頭:

  • 必要條件:Content-Type: application/json
    • 允許選用 ; charset=utf-8
  • 選用:Authorization: Bearer <token>
    • 已登入使用者的 Firebase Authentication 使用者 ID 權杖,用於提出要求。後端會自動驗證這個權杖,並在處理常式的 context 中提供。如果權杖無效,系統就會拒絕要求。
  • 選用:Firebase-Instance-ID-Token: <iid>
    • Firebase 用戶端 SDK 的 FCM 註冊權杖。這必須是字串。這項資訊可在處理常式的 context 中取得。用於指定推播通知目標。
  • 選用:X-Firebase-AppCheck: <token>
    • 提出要求的用戶端應用程式提供的 Firebase App Check 權杖。後端會自動驗證並解碼這個權杖,然後將 appId 插入處理常式的 context。如果無法驗證符記,系統會拒絕要求。(適用於 SDK 3.14.0 以上版本)

如果包含任何其他標頭,系統會拒絕要求,詳情請參閱下方的回應文件。

注意:在 JavaScript 用戶端中,這些要求會觸發 CORS OPTIONS 預檢,原因如下:

  • 不允許application/json。必須是 text/plainapplication/x-www-form-urlencoded
  • Authorization 標頭不是 CORS 安全許可要求標頭
  • 同樣地,系統也不允許使用其他標頭。

可呼叫的觸發條件會自動處理這些 OPTIONS 要求。

要求主體

HTTP 要求的本文應為 JSON 物件,並包含下列任一欄位:

  • 必要:data - 傳遞至函式的引數。可以是任何有效的 JSON 值。系統會根據下述序列化格式,自動將這些值解碼為原生 JavaScript 型別。

如果要求中包含其他欄位,後端會將要求視為格式錯誤並拒絕。

回覆格式:狀態碼

在回應中,錯誤可能會導致不同的 HTTP 狀態碼和字串狀態碼。

  1. 如果在叫用 client 觸發程序前發生 HTTP 錯誤,系統不會將回應視為用戶端函式處理。舉例來說,如果用戶端嘗試叫用不存在的函式,就會收到 404 Not Found 回應。

  2. 如果叫用用戶端觸發條件,但要求格式有誤 (例如不是 JSON、含有無效欄位或缺少 data 欄位),系統會拒絕要求並傳回 400 Bad Request,錯誤代碼為 INVALID_ARGUMENT

  3. 如果要求中提供的驗證權杖無效,系統會拒絕要求並傳回 401 Unauthorized,錯誤代碼為 UNAUTHENTICATED

  4. 如果要求中提供的 FCM 註冊權杖無效,系統行為將不確定。除非用於透過 FCM 傳送推播通知,否則系統不會在每個要求中檢查權杖。

  5. 如果叫用可呼叫的觸發程序,但因未處理的例外狀況而失敗,或傳回失敗的 Promise,系統會以 500 Internal Server Error 拒絕要求,並傳回 INTERNAL 的錯誤代碼。以免程式碼錯誤不慎暴露給使用者。

  6. 如果叫用可呼叫函式並使用為可呼叫函式提供的 API 傳回明確的錯誤情況,要求就會失敗。傳回的 HTTP 狀態碼是根據 code.proto 中定義的錯誤狀態與 HTTP 狀態的官方對應關係。傳回的特定錯誤代碼、訊息和詳細資料會編碼至回應本文中,詳情如下。也就是說,如果函式傳回狀態為 OK 的明確錯誤,則回應的狀態為 200 OK,但回應中會設定 error 欄位。

  7. 如果用戶端觸發程序成功,回應狀態為 200 OK

回應格式:標頭

回應包含下列標頭:

  • Content-Type: application/json
  • 允許選用 ; charset=utf-8

回應主體

用戶端端點的回應一律為 JSON 物件。至少包含 resulterror,以及任何選用欄位。如果回應不是 JSON 物件,或不包含 dataerror,用戶端 SDK 應將要求視為失敗,並傳回 Google 錯誤碼 INTERNAL (13)

  • error - 如果這個欄位存在,則無論 HTTP 狀態碼為何,或 data 是否也存在,要求都會視為失敗。這個欄位的值應為標準 Google Cloud HTTP 對應格式的錯誤 JSON 物件,並包含 statusmessage 和 (選用) details 的欄位。不得包含 code 欄位。如果 status 欄位未設定或值無效,用戶端應根據 code.proto 將狀態視為 INTERNAL。如果存在 details,則會視情況納入附加至用戶端 SDK 錯誤的任何使用者資訊。
    注意:此處的 details 欄位是使用者提供的值。這不一定是 Google Status 格式中以原型為鍵的值清單。
  • result - 函式傳回的值。可以是任何有效的 JSON 值。firebase-functions SDK 會自動將使用者傳回的值編碼為這種 JSON 格式。用戶端 SDK 會根據下述序列化格式,自動將這些參數解碼為原生型別。

如果還有其他欄位,請忽略。

序列化

要求和回應的任意資料酬載序列化格式相同。

為確保平台一致性,這些值會以 JSON 格式編碼,如同 proto3 通訊協定緩衝區中的 Any 欄位值,並使用標準 JSON 對應。系統會直接編碼 nullintdoublestring 等簡單型別的值,且不會包含明確型別。因此,floatdouble 的編碼方式相同,您可能不知道通話另一端收到的是哪個字元。如果類型不是 JSON 原生類型,系統會使用值的型別 proto3 編碼。詳情請參閱 Any JSON 編碼說明文件

允許的類型如下:

  • null - null
  • int (有符號或無符號,最多 32 位元) - 例如 3-30
  • 浮點數 - 例如 3.14
  • 雙引號 - 例如 3.14
  • 布林值 - truefalse
  • 字串 - 例如 "hello world"
  • map<string, any=""> - e.g. {"x": 3}</string,>
  • 清單 - 例如 [1, 2, 3]
  • long (有符號或無符號,最多 64 位元) - [詳情請參閱下文]

系統不支援 floatdoubleNaNInfinity 值。

請注意,long 是 JSON 中通常不允許的特殊類型,但 proto3 規格涵蓋此類型。舉例來說,這些會編碼為:

long

{
    '@type': 'type.googleapis.com/google.protobuf.Int64Value',
    'value': '-123456789123456'
}

unsigned long

{
    '@type': 'type.googleapis.com/google.protobuf.UInt64Value',
    'value': '123456789123456'
}

一般而言,@type 鍵應視為保留鍵,不應用於傳入的地圖。

由於簡單型別未指定型別,部分值會在透過網路傳輸後變更型別。傳入的 float 會變成 double。例如 short 會變成 int。在 Android 中,清單值同時支援 ListJSONArray。在這種情況下,傳遞 JSONArray 會產生 List

如果還原序列化含有不明 @type 欄位的對應,系統會將其保留為對應。這樣一來,開發人員就能在傳回值中新增欄位,而不必擔心舊版用戶端無法運作。

程式碼範例

本節的範例說明如何編碼下列項目:

  • Swift 中的 callable.call 範例
  • 呼叫的成功回應
  • 呼叫的失敗回應

Swift 中用於編碼的 Callable.call 範例

callable.call([
    "aString": "some string",
    "anInt": 57,
    "aFloat": 1.23,
    "aLong": -123456789123456 as Int64
])

要求標頭:

Method: POST
Content-Type: application/json; charset=utf-8
Authorization: Bearer some-auth-token
Firebase-Instance-ID-Token: some-iid-token

要求主體:

{
    "data": {
        "aString": "some string",
        "anInt": 57,
        "aFloat": 1.23,
        "aLong": {
            "@type": "type.googleapis.com/google.protobuf.Int64Value",
            "value": "-123456789123456"
        }
    }
}

要編碼的回覆

return {
    "aString": "some string",
    "anInt": 57,
    "aFloat": 1.23
};

成功的回應標頭:

200 OK
Content-Type: application/json; charset=utf-8

成功的回應主體:

{
    "response": {
        "aString": "some string",
        "anInt": 57,
        "aFloat": 1.23
    }
}

要編碼的失敗回應

throw new HttpsError("unauthenticated", "Request had invalid credentials.", {
  "some-key": "some-value"
});

失敗的回應標頭:

401 UNAUTHENTICATED
Content-Type: application/json; charset=utf-8

失敗的回應主體:

{
    "error": {
        "message": "Request had invalid credentials.",
        "status": "UNAUTHENTICATED",
        "details": {
            "some-key": "some-value"
        }
    }
}