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 預檢,原因如下:

可呼叫的觸發程序會自動處理這些 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 物件。至少包含 result 或 error,以及任何選用欄位。如果回應不是 JSON 物件,或不包含 data 或 error,用戶端 SDK 應將要求視為失敗,並傳回 Google 錯誤碼 INTERNAL (13)。

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

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

序列化

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

為確保平台一致性,這些值會以 JSON 格式編碼,就像是 proto3 通訊協定緩衝區中的 Any 欄位值,並使用標準 JSON 對應。系統會直接編碼 null、int、double 或 string 等簡單型別的值,且不會包含明確型別。因此,float 和 double 的編碼方式相同,您可能無法得知通話另一端收到的是哪個字元。對於非 JSON 原生的型別,系統會使用值的型別 proto3 編碼。詳情請參閱 Any JSON 編碼說明文件。

允許的類型如下:

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

系統不支援 float 和 double 的 NaN 和 Infinity 值。

請注意,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 中,清單值同時支援 List 和 JSONArray。在這種情況下,傳遞 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"
        }
    }
}