مواصفات البروتوكول لـ https.onCall

إنّ مشغّل https.onCall في Cloud Functions هو مشغّل HTTPS بتنسيق محدّد للطلب والاستجابة. يقدّم هذا القسم مواصفات لتنسيقات طلبات HTTPS واستجاباتها التي تستخدمها حِزم SDK للعميل لتنفيذ واجهة برمجة التطبيقات. قد تكون هذه المعلومات مفيدة إذا لم يكن بالإمكان تلبية متطلباتك باستخدام حِزم SDK لنظام Android أو منصات Apple أو الويب.

تنسيق الطلب: العناوين

يجب أن يكون طلب HTTP لنقطة نهاية مشغّل قابل للاستدعاء POST مع العناوين التالية:

  • مطلوب: Content-Type: application/json
    • يُسمح باستخدام ; charset=utf-8 اختياريًا.
  • اختياري: Authorization: Bearer <token>
  • اختياري: Firebase-Instance-ID-Token: <iid>
    • رمز تسجيل FCM من حزمة Firebase SDK للعميل يجب أن يكون هذا الرمز سلسلة. وهو متاح في context المعالج. ويُستخدَم لاستهداف الإشعارات الفورية.
  • اختياري: X-Firebase-AppCheck: <token>
    • رمز ميزة "فحص التطبيقات من Firebase" الذي يقدّمه تطبيق العميل الذي يرسل الطلب يتحقّق النظام الخلفي تلقائيًا من هذا الرمز ويفك ترميزه، ويُدرِج appId في context المعالج. إذا تعذّر التحقّق من الرمز، يتم رفض الطلب. (متاح لإصدار حزمة SDK >=3.14.0)

إذا تم تضمين أي عناوين أخرى، يتم رفض الطلب، كما هو موضّح في مستندات الاستجابة أدناه.

ملاحظة: في عملاء JavaScript، تؤدي هذه الطلبات إلى تشغيل عملية فحص مسبق لطلبات OPTIONS في CORS، للأسباب التالية:

  • لا يُسمح باستخدام application/json. يجب أن يكون text/plain أو application/x-www-form-urlencoded.
  • عنوان Authorization ليس عنوان طلب مدرَجًا في القائمة الآمنة لـ CORS.
  • وبالمثل، لا يُسمح باستخدام العناوين الأخرى.

يتعامل المشغّل القابل للاستدعاء تلقائيًا مع طلبات OPTIONS هذه.

نص الطلب

يجب أن يكون نص طلب HTTP كائن JSON يتضمّن أيًا من الحقول التالية:

  • مطلوب: data : الوسيطة التي تم تمريرها إلى الدالة يمكن أن تكون أي قيمة JSON صالحة. يتم فك ترميزها تلقائيًا إلى أنواع JavaScript الأصلية وفقًا لتنسيق التسلسل الموضّح أدناه.

إذا كانت هناك أي حقول أخرى في الطلب، يعتبر النظام الخلفي أنّ الطلب غير صالح ويتم رفضه.

تنسيق الردّ: رموز الحالة

هناك عدة حالات قد تؤدي إلى رموز حالة HTTP مختلفة و رموز حالة سلسلة لـ الأخطاء في الاستجابة.

  1. في حال حدوث خطأ HTTP قبل استدعاء مشغّل client، لا يتم التعامل مع الاستجابة كدالة عميل. على سبيل المثال، إذا حاول أحد العملاء استدعاء دالة غير موجودة، سيتلقّى استجابة 404 Not Found.

  2. إذا تم استدعاء مشغّل العميل، ولكن كان الطلب بتنسيق غير صحيح، مثل عدم كونه JSON أو احتوائه على حقول غير صالحة أو عدم تضمينه حقل data، يتم رفض الطلب مع عرض 400 Bad Request ورمز الخطأ INVALID_ARGUMENT.

  3. إذا كان رمز المصادقة المقدَّم في الطلب غير صالح، يتم رفض الطلب مع عرض 401 Unauthorized ورمز الخطأ UNAUTHENTICATED.

  4. إذا كان رمز تسجيل FCM المقدَّم في الطلب غير صالح، يكون السلوك غير محدّد. لا يتم التحقّق من الرمز في كل طلب، إلا عند استخدامه لإرسال إشعار فوري باستخدام FCM.

  5. إذا تم استدعاء المشغّل القابل للاستدعاء، ولكن تعذّر تنفيذه بسبب استثناء لم تتم معالجته أو عرض وعد فاشل، يتم رفض الطلب مع عرض 500 Internal Server Error ورمز الخطأ INTERNAL. يمنع ذلك عرض أخطاء البرمجة للمستخدمين النهائيين عن طريق الخطأ.

  6. إذا تم استدعاء الدالة القابلة للاستدعاء وعرضت حالة خطأ صريحة باستخدام واجهة برمجة التطبيقات المقدَّمة للدوال القابلة للاستدعاء، سيفشل الطلب. يستند رمز حالة HTTP الذي يتم عرضه إلى الربط الرسمي لحالة الخطأ بحالة HTTP، كما هو محدّد في code.proto. يتم ترميز رمز الخطأ والرسالة والتفاصيل المحدّدة التي يتم عرضها في نص الاستجابة كما هو موضّح أدناه. يعني ذلك أنّه إذا كانت الدالة تعرِض خطأً صريحًا بحالة 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 موجودًا أيضًا. يجب أن تكون قيمة هذا الحقل كائن JSON بتنسيق الربط القياسي لـ Google Cloud HTTP للأخطاء، مع حقول status وmessage وdetails (اختياريًا). يجب عدم تضمين الحقل code. إذا لم يتم ضبط الحقل status أو كانت قيمته غير صالحة، يجب أن يتعامل العميل مع الحالة على أنّها INTERNAL، وفقًا لـ code.proto. إذا كان details موجودًا، يتم تضمينه في أي معلومات مستخدم مرفقة بالخطأ في حزمة SDK للعميل، إذا كان ذلك ممكنًا.
    ملاحظة: الحقل details هنا هو قيمة يقدّمها المستخدم. وليس بالضرورة قائمة بالقيم التي يتم تحديد مفاتيحها حسب نوع proto كما في تنسيق Status من Google.
  • result : القيمة التي تعرِضها الدالة يمكن أن تكون أي قيمة JSON صالحة. تعمل حزمة firebase-functions SDK تلقائيًا على ترميز القيمة التي يعرِضها المستخدم بهذا التنسيق JSON. تعمل حِزم SDK للعميل تلقائيًا على فك ترميز هذه المَعلمات إلى أنواع أصلية وفقًا لتنسيق التسلسل الموضّح أدناه.

إذا كانت هناك حقول أخرى، يجب تجاهلها.

نشر الحلقات على نحو متسلسِل

يكون تنسيق التسلسل لحِملات البيانات العشوائية هو نفسه لكل من الطلب والاستجابة.

لضمان الاتساق بين المنصات، يتم ترميز هذه البيانات بتنسيق JSON كما لو كانت قيمة حقل Any في مخزن مؤقت لبروتوكول proto3، باستخدام ربط JSON العادي. يتم ترميز قيم الأنواع البسيطة، مثل null أو int أو double أو string مباشرةً، ولا تتضمّن نوعها الصريح. لذلك، يتم ترميز float وdouble بالطريقة نفسها، وقد لا تعرف النوع الذي يتم تلقّيه على الطرف الآخر من المكالمة. بالنسبة إلى الأنواع غير الأصلية في JSON، يتم استخدام ترميز proto3 المكتوب للقيمة. لمزيد من المعلومات، اطّلِع على مستندات ترميز Any JSON.

يُسمح بالأنواع التالية:

  • null - null
  • int (موقّع أو غير موقّع، يصل إلى 32 بت) - مثلاً 3 أو -30
  • float - مثلاً 3.14
  • double - مثلاً 3.14
  • boolean - true أو false
  • string - مثلاً "hello world"
  • map<string, any=""> - مثلاً {"x": 3}</string,>
  • list - مثلاً [1, 2, 3]
  • long (موقّع أو غير موقّع، يصل إلى 64 بت) - [اطّلِع على التفاصيل أدناه]

لا يُسمح باستخدام القيم NaN وInfinity لـ float وdouble.

يُرجى العِلم أنّ 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. يصبح shortint وما إلى ذلك. في Android، يُسمح باستخدام كل من List وJSONArray لقيم القوائم. في هذه الحالات، سيؤدي تمرير JSONArray إلى List.

إذا تم إلغاء تسلسل خريطة تتضمّن حقل @type غير معروف، يتم تركها كخريطة. يسمح ذلك للمطوّرين بإضافة حقول بأنواع جديدة إلى القيم التي يعرضونها بدون إيقاف عمل العملاء الأقدم.

عيّنات تعليمات برمجية

توضّح العيّنات في هذا القسم كيفية ترميز ما يلي:

  • مثال على callable.call في Swift
  • استجابة ناجحة للمكالمة
  • استجابة فاشلة للمكالمة

مثال على Callable.call في Swift للترميز

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"
        }
    }
}