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 UnauthorizedUNAUTHENTICATED 錯誤代碼。

  4. 如果要求中提供的 FCM 註冊權杖無效,系統就不會定義該行為。權杖只會在透過 FCM 傳送推播通知時,才會在每個要求中檢查。

  5. 如果可呼叫的觸發事件遭到叫用,但因未處理的例外狀況而失敗,或傳回失敗的承諾,要求會遭到 500 Internal Server Error 拒絕,並傳回 INTERNAL 錯誤代碼。這可以避免使用者意外看見程式設計錯誤。

  6. 如果叫用可呼叫函式,並使用為可呼叫函式提供的 API 傳回明確的錯誤情況,則要求會失敗。系統會根據 code.proto 中定義的錯誤狀態與 HTTP 狀態官方對應,傳回 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。這個欄位的值應為 JSON 物件,採用標準 Google Cloud HTTP 對應格式,用於錯誤,並包含 statusmessage 和 (選用) details 欄位。請勿納入 code 欄位。如果 status 欄位未設定或為無效值,用戶端應根據 code.proto 將狀態視為 INTERNAL。如果有 details,則會納入用戶資訊,並附加至用戶端 SDK 中的錯誤 (如適用)。
    注意:此處的 details 欄位是使用者提供的值。不一定是按 Proto 類型鍵入的值清單,如 Google Status 格式。
  • result:函式傳回的值。可以是任何有效的 JSON 值。firebase-functions SDK 會自動將使用者傳回的值編碼為 JSON 格式。根據下列說明的序列化格式,用戶端 SDK 會自動將這些參數解碼為原生類型。

如果有其他欄位,系統會忽略這些欄位。

序列化

無論是要求還是回應,任意資料酬載的序列化格式都相同。

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

可使用的類型如下:

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

系統不支援 floatdoubleNaNInfinity 值。

請注意,long 是 JSON 中通常不允許的特殊類型,但已包含在 proto3 規格中。例如,這些項目會編碼為:

long

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

無符號長整數

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

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

由於簡單類型未指定類型,因此部分值會在傳送至網路後變更類型。傳入的 float 會變成 doubleshort 會變成 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"
        }
    }
}