فراخوانی توابع از برنامه شما

Cloud Functions for Firebase به شما امکان می‌دهند توابع را مستقیماً از یک برنامه فایربیس فراخوانی کنید. برای فراخوانی یک تابع از برنامه خود به این روش، یک تابع قابل فراخوانی HTTP را در Cloud Functions بنویسید و مستقر کنید، و سپس منطق کلاینت را برای فراخوانی تابع از برنامه خود اضافه کنید.

مهم است که به خاطر داشته باشید که توابع قابل فراخوانی HTTP مشابه توابع HTTP هستند اما دقیقاً یکسان نیستند . برای استفاده از توابع قابل فراخوانی HTTP، باید از SDK کلاینت برای پلتفرم خود به همراه API بک‌اند (یا پیاده‌سازی پروتکل) استفاده کنید. توابع قابل فراخوانی این تفاوت‌های کلیدی را با توابع HTTP دارند:

  • با استفاده از موارد قابل فراخوانی، توکن‌های Firebase Authentication ، توکن‌های FCM و توکن‌های App Check ، در صورت وجود، به طور خودکار در درخواست‌ها گنجانده می‌شوند.
  • تریگر به طور خودکار بدنه درخواست را deserialize کرده و توکن‌های احراز هویت را اعتبارسنجی می‌کند.

کیت توسعه نرم‌افزار Firebase برای Cloud Functions نسل دوم و بالاتر با حداقل نسخه‌های SDK کلاینت فایربیس زیر برای پشتیبانی از توابع قابل فراخوانی HTTPS همکاری می‌کند:

  • کیت توسعه نرم‌افزار Firebase برای پلتفرم‌های Apple ۱۲.۴.۰
  • کیت توسعه نرم‌افزار Firebase برای Android ۲۲.۰.۱
  • کیت توسعه نرم‌افزار وب ماژولار فایربیس نسخه ۹.۷.۰

اگر می‌خواهید قابلیت‌های مشابهی را به برنامه‌ای که روی یک پلتفرم پشتیبانی نشده ساخته شده است اضافه کنید، به مشخصات پروتکل https.onCall مراجعه کنید. بقیه این راهنما دستورالعمل‌هایی در مورد نحوه نوشتن، استقرار و فراخوانی یک تابع قابل فراخوانی HTTP برای پلتفرم‌های اپل، اندروید، وب، C++ و Unity ارائه می‌دهد.

تابع قابل فراخوانی را بنویسید و مستقر کنید

نمونه‌های کد در این بخش بر اساس یک نمونه راهنمای کامل هستند که نحوه ارسال درخواست به یک تابع سمت سرور و دریافت پاسخ با استفاده از یکی از SDK های کلاینت را نشان می‌دهد. برای شروع، ماژول‌های مورد نیاز را وارد کنید:

نود جی اس

// Dependencies for callable functions.
const {onCall, HttpsError} = require("firebase-functions/https");
const {logger} = require("firebase-functions");

// Dependencies for the addMessage function.
const {getDatabase} = require("firebase-admin/database");
const sanitizer = require("./sanitizer");

پایتون

# Dependencies for callable functions.
from firebase_functions import https_fn, options

# Dependencies for writing to Realtime Database.
from firebase_admin import db, initialize_app

از کنترل‌کننده‌ی درخواست برای پلتفرم خود ( functions.https.onCall ) یا on_call ) برای ایجاد یک تابع قابل فراخوانی HTTPS استفاده کنید. این متد یک پارامتر درخواست دریافت می‌کند:

نود جی اس

// Saves a message to the Firebase Realtime Database but sanitizes the
// text by removing swearwords.
exports.addmessage = onCall((request) => {
  // ...
});

پایتون

@https_fn.on_call()
def addmessage(req: https_fn.CallableRequest) -> Any:
    """Saves a message to the Firebase Realtime Database but sanitizes the text
    by removing swear words."""

پارامتر request شامل داده‌های ارسالی از برنامه کلاینت و همچنین زمینه اضافی مانند وضعیت احراز هویت است. برای مثال، برای یک تابع قابل فراخوانی که یک پیام متنی را در Realtime Database ذخیره می‌کند، data می‌توانند شامل متن پیام به همراه اطلاعات احراز هویت در auth :

نود جی اس

// Message text passed from the client.
const text = request.data.text;
// Authentication / user information is automatically added to the request.
const uid = request.auth.uid;
const name = request.auth.token.name || null;
const picture = request.auth.token.picture || null;
const email = request.auth.token.email || null;

پایتون

# Message text passed from the client.
text = req.data["text"]
# Authentication / user information is automatically added to the request.
uid = req.auth.uid
name = req.auth.token.get("name", "")
picture = req.auth.token.get("picture", "")
email = req.auth.token.get("email", "")

فاصله بین محل تابع فراخوانی شونده و محل کلاینت فراخوانی کننده می‌تواند باعث تأخیر شبکه شود. برای بهینه‌سازی عملکرد، در صورت لزوم، مکان تابع را مشخص کنید و مطمئن شوید که هنگام مقداردهی اولیه SDK در سمت کلاینت، مکان تابع فراخوانی شونده را با مکان تنظیم شده هم‌تراز می‌کنید.

در صورت تمایل، می‌توانید یک گواهی App Check ضمیمه کنید تا از منابع پشتیبان خود در برابر سوءاستفاده، مانند کلاهبرداری در صورتحساب یا فیشینگ، محافظت کنید. برای Cloud Functions به بخش «فعال کردن اجرای App Check مراجعه کنید.

نتیجه را دوباره ارسال کنید

برای ارسال داده‌ها به کلاینت، داده‌هایی را برگردانید که می‌توانند به صورت JSON کدگذاری شوند. برای مثال، برای برگرداندن نتیجه یک عملیات جمع:

نود جی اس

// returning result.
return {
  firstNumber: firstNumber,
  secondNumber: secondNumber,
  operator: "+",
  operationResult: firstNumber + secondNumber,
};

پایتون

return {
    "firstNumber": first_number,
    "secondNumber": second_number,
    "operator": "+",
    "operationResult": first_number + second_number
}

متن پاک‌سازی‌شده از مثال متن پیام، هم به کلاینت و هم به Realtime Database بازگردانده می‌شود. در Node.js، این کار می‌تواند به صورت غیرهمزمان با استفاده از یک promise جاوا اسکریپت انجام شود:

نود جی اس

// Saving the new message to the Realtime Database.
const sanitizedMessage = sanitizer.sanitizeText(text); // Sanitize message.

return getDatabase().ref("/messages").push({
  text: sanitizedMessage,
  author: {uid, name, picture, email},
}).then(() => {
  logger.info("New Message written");
  // Returning the sanitized message to the client.
  return {text: sanitizedMessage};
})

پایتون

# Saving the new message to the Realtime Database.
sanitized_message = sanitize_text(text)  # Sanitize message.
db.reference("/messages").push({  # type: ignore
    "text": sanitized_message,
    "author": {
        "uid": uid,
        "name": name,
        "picture": picture,
        "email": email
    }
})
print("New message written")

# Returning the sanitized message to the client.
return {"text": sanitized_message}

تابع شما باید یک مقدار یا در مورد Node.js، یک Promise که با یک مقدار حل می‌شود را برگرداند. در غیر این صورت، تابع ممکن است قبل از ارسال داده‌ها به کلاینت خاتمه یابد. برای راهنمایی به بخش خاتمه توابع مراجعه کنید.

ارسال و دریافت نتایج استریمینگ

توابع فراخوانی‌پذیر مکانیزم‌هایی برای مدیریت نتایج استریمینگ دارند. اگر موردی دارید که نیاز به استریمینگ دارد، می‌توانید استریمینگ را در درخواست فراخوانی‌پذیر پیکربندی کنید و سپس از روش مناسب از SDK کلاینت برای فراخوانی تابع استفاده کنید.

ارسال نتایج پخش زنده

برای استریم کردن کارآمد نتایجی که در طول زمان تولید می‌شوند، مانند تعدادی از درخواست‌های API جداگانه یا یک API تولیدی هوش مصنوعی، ویژگی acceptsStreaming را در درخواست قابل فراخوانی خود بررسی کنید. وقتی این ویژگی روی true تنظیم شده باشد، می‌توانید نتایج را با response.sendChunk() به کلاینت استریم کنید.

برای مثال، اگر یک برنامه نیاز به بازیابی داده‌های پیش‌بینی آب و هوا برای چندین مکان داشته باشد، تابع فراخوانی‌شده می‌تواند پیش‌بینی هر مکان را به‌طور جداگانه به کلاینت‌هایی که درخواست پاسخ استریمینگ کرده‌اند ارسال کند، به‌جای اینکه آنها را منتظر بگذارد تا همه درخواست‌های پیش‌بینی پاسخ داده شوند:

exports.getForecast = onCall(async (request, response) => {
  if (request.data?.locations?.length < 1) {
    throw new HttpsError("invalid-argument", "Missing locations to forecast");
  }

  // fetch forecast data for all requested locations
  const allRequests = request.data.locations.map(
      async ({latitude, longitude}) => {
        const forecast = await weatherForecastApi(latitude, longitude);
        const result = {latitude, longitude, forecast};

        // clients that support streaming will have each
        // forecast streamed to them as they complete
        if (request.acceptsStreaming) {
          response.sendChunk(result);
        }

        return result;
      },
  );

  // Return the full set of data to all clients
  return Promise.all(allRequests);
});

توجه داشته باشید که نحوه عملکرد response.sendChunk() به جزئیات خاصی از درخواست کلاینت بستگی دارد:

  1. اگر کلاینت درخواست پاسخ استریمینگ کند: response.sendChunk(data) قطعه داده را فوراً ارسال می‌کند.

  2. اگر کلاینت درخواست پاسخ استریمینگ نکند: response.sendChunk() برای آن فراخوانی کاری انجام نمی‌دهد. پاسخ کامل پس از آماده شدن تمام داده‌ها ارسال می‌شود.

برای تعیین اینکه آیا کلاینت درخواست پاسخ استریمینگ (streaming) را دارد یا خیر، ویژگی request.acceptsStreaming را بررسی کنید. برای مثال، اگر request.acceptsStreaming برابر با false باشد، ممکن است تصمیم بگیرید از هرگونه کار فشرده با منابع که به طور خاص مربوط به آماده‌سازی یا ارسال تکه‌های جداگانه است، صرف نظر کنید، زیرا کلاینت انتظار تحویل افزایشی را ندارد.

دریافت نتایج پخش زنده

در یک سناریوی معمول، کلاینت با استفاده از متد .stream درخواست استریمینگ می‌کند و سپس نتایج را مرور می‌کند:

سویفت

func listenToWeatherForecast() async throws {
    isLoading = true
    defer { isLoading = false }

    Functions
      .functions(region: "us-central1")
    let getForecast: Callable<WeatherRequest, StreamResponse<WeatherResponse, [WeatherResponse]>> = Functions.functions().httpsCallable("getForecast")

    let request = WeatherRequest(locations: locations)
    let stream = try getForecast.stream(request)

    for try await response in stream {
      switch response {
      case .message(let singleResponse):
        weatherData["\(singleResponse.latitude),\(singleResponse.longitude)"] = singleResponse
      case .result(let arrayOfResponses):
        for response in arrayOfResponses {
          weatherData["\(response.latitude),\(response.longitude)"] = response
        }
        print("Stream ended.")
        return
      }
    }
  }

Web

// Get the callable by passing an initialized functions SDK.
const getForecast = httpsCallable(functions, "getForecast");

// Call the function with the `.stream()` method to start streaming.
const { stream, data } = await getForecast.stream({
  locations: favoriteLocations,
});

// The `stream` async iterable returned by `.stream()`
// will yield a new value every time the callable
// function calls `sendChunk()`.
for await (const forecastDataChunk of stream) {
  // update the UI every time a new chunk is received
  // from the callable function
  updateUi(forecastDataChunk);
}

// The `data` promise resolves when the callable
// function completes.
const allWeatherForecasts = await data;
finalizeUi(allWeatherForecasts);

همانطور که نشان داده شده است، روی stream تکرارشونده ناهمگام حلقه بزنید. منتظر ماندن برای data به کلاینت نشان می‌دهد که درخواست کامل شده است.

Kotlin

// Get the callable by passing an initialized functions SDK.
val getForecast = functions.getHttpsCallable("getForecast");

// Call the function with the `.stream()` method and convert it to a flow
getForecast.stream(
  mapOf("locations" to favoriteLocations)
).asFlow().collect { response ->
  when (response) {
    is StreamResponse.Message -> {
      // The flow will emit a [StreamResponse.Message] value every time the
      // callable function calls `sendChunk()`.
      val forecastDataChunk = response.message.data as Map<String, Any>
      // Update the UI every time a new chunk is received
      // from the callable function
      updateUI(
        forecastDataChunk["latitude"] as Double,
        forecastDataChunk["longitude"] as Double,
        forecastDataChunk["forecast"] as Double,
      )
    }
    is StreamResponse.Result -> {
      // The flow will emit a [StreamResponse.Result] value when the
      // callable function completes.
      val allWeatherForecasts = response.result.data as List<Map<String, Any>>
      finalizeUI(allWeatherForecasts)
    }
  }
}

برای استفاده از تابع افزونه‌ی asFlow() ، کتابخانه‌ی org.jetbrains.kotlinx:kotlinx-coroutines-reactive به عنوان یک وابستگی به فایل build.gradle(.kts) برنامه اضافه کنید.

Java

// Get the callable by passing an initialized functions SDK.
HttpsCallableReference getForecast = mFunctions.getHttpsCallable("getForecast");
getForecast.stream(
  new HashMap<String, Object>() {{
    put("locations", favoriteLocations);
  }}
).subscribe(new Subscriber<StreamResponse>() {
  @Override
  public void onSubscribe(Subscription subscription) {
    subscription.request(Long.MAX_VALUE);
  }

  @Override
  public void onNext(StreamResponse streamResponse) {
    if (streamResponse instanceof StreamResponse.Message) {
      // The flow will emit a [StreamResponse.Message] value every time the
      // callable function calls `sendChunk()`.
      StreamResponse.Message response = (StreamResponse.Message) streamResponse;
      Map<String, Object> forecastDataChunk =
        (Map<String, Object>) response.getMessage().getData();
      // Update the UI every time a new chunk is received
      // from the callable function
      updateUI(
        (double) forecastDataChunk.get("latitude"),
        (double) forecastDataChunk.get("longitude"),
        (double) forecastDataChunk.get("forecast")
      );
    } else if(streamResponse instanceof StreamResponse.Result) {
      // The flow will emit a [StreamResponse.Result] value when the
      // callable function completes.
      StreamResponse.Result response = (StreamResponse.Result) streamResponse;
      List<Map<String, Object>> allWeatherForecasts =
        (List<Map<String, Object>>) response.getResult().getData();
      finalizeUI();
    }
  }

  @Override
  public void onError(Throwable throwable) {
    // an error occurred in the function
  }

  @Override
  public void onComplete() {

  }
});

پیکربندی CORS (اشتراک‌گذاری منابع بین مبدا)

از گزینه cors برای کنترل اینکه کدام ریشه‌ها می‌توانند به تابع شما دسترسی داشته باشند، استفاده کنید.

به طور پیش‌فرض، توابع قابل فراخوانی CORS را طوری پیکربندی کرده‌اند که درخواست‌ها را از همه مبدأها مجاز بدانند. برای مجاز کردن برخی از درخواست‌های بین مبدأیی، اما نه همه آنها، لیستی از دامنه‌های خاص یا عبارات منظم را که باید مجاز باشند، ارسال کنید. به عنوان مثال:

نود جی اس

const { onCall } = require("firebase-functions/v2/https");

exports.getGreeting = onCall(
  { cors: [/firebase\.com$/, "https://flutter.com"] },
  (request) => {
    return "Hello, world!";
  }
);

برای جلوگیری از درخواست‌های بین‌مرجعی، سیاست cors را روی false تنظیم کنید.

مدیریت خطاها

برای اطمینان از اینکه کلاینت جزئیات خطای مفیدی را دریافت می‌کند، با پرتاب کردن (یا برای Node.js که یک Promise رد شده را با آن برمی‌گرداند) یک نمونه از functions.https.HttpsError یا https_fn.HttpsError ، خطاها را از یک تابع قابل فراخوانی برگردانید. خطا دارای یک ویژگی code است که می‌تواند یکی از مقادیر ذکر شده در کدهای وضعیت gRPC باشد. خطاها همچنین دارای یک message رشته‌ای هستند که به طور پیش‌فرض یک رشته خالی است. آنها همچنین می‌توانند یک فیلد details اختیاری با مقدار دلخواه داشته باشند. اگر خطایی غیر از خطای HTTPS از توابع شما پرتاب شود، کلاینت شما به جای آن خطایی با پیام INTERNAL و کد internal دریافت می‌کند.

برای مثال، یک تابع می‌تواند خطاهای اعتبارسنجی داده‌ها و احراز هویت را به همراه پیام‌های خطا به کلاینت فراخواننده ارسال کند:

نود جی اس

// Checking attribute.
if (!(typeof text === "string") || text.length === 0) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new HttpsError("invalid-argument", "The function must be called " +
          "with one arguments \"text\" containing the message text to add.");
}
// Checking that the user is authenticated.
if (!request.auth) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new HttpsError("failed-precondition", "The function must be " +
          "called while authenticated.");
}

پایتون

# Checking attribute.
if not isinstance(text, str) or len(text) < 1:
    # Throwing an HttpsError so that the client gets the error details.
    raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
                              message=('The function must be called with one argument, "text",'
                                       " containing the message text to add."))

# Checking that the user is authenticated.
if req.auth is None:
    # Throwing an HttpsError so that the client gets the error details.
    raise https_fn.HttpsError(code=https_fn.FunctionsErrorCode.FAILED_PRECONDITION,
                              message="The function must be called while authenticated.")

تابع قابل فراخوانی را مستقر کنید

بعد از اینکه یک تابع فراخوانی‌شده‌ی کامل را در index.js ذخیره کردید، هنگام اجرای firebase deploy این تابع به همراه تمام توابع دیگر مستقر می‌شود. برای استقرار فقط تابع فراخوانی‌شده، از آرگومان --only همانطور که نشان داده شده است برای انجام استقرارهای جزئی استفاده کنید:

firebase deploy --only functions:addMessage

اگر هنگام استقرار توابع با خطاهای مجوز مواجه شدید، مطمئن شوید که نقش‌های IAM مناسب به کاربری که دستورات استقرار را اجرا می‌کند، اختصاص داده شده است.

محیط توسعه کلاینت خود را تنظیم کنید

مطمئن شوید که پیش‌نیازها را رعایت می‌کنید، سپس وابستگی‌ها و کتابخانه‌های کلاینت مورد نیاز را به برنامه خود اضافه کنید.

آی‌او‌اس+

برای افزودن Firebase به برنامه اپل خود، دستورالعمل‌ها را دنبال کنید.

برای نصب و مدیریت وابستگی‌های Firebase از Swift Package Manager استفاده کنید.

  1. در Xcode، با باز کردن پروژه برنامه خود، به File > Add Packages بروید.
  2. وقتی از شما خواسته شد، مخزن SDK پلتفرم‌های اپل فایربیس را اضافه کنید:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. کتابخانه Cloud Functions انتخاب کنید.
  5. پرچم -ObjC را به بخش Other Linker Flags در تنظیمات ساخت هدف خود اضافه کنید.
  6. پس از اتمام، Xcode به طور خودکار شروع به حل و دانلود وابستگی‌های شما در پس‌زمینه می‌کند.

Web

  1. برای افزودن Firebase به برنامه وب خود، دستورالعمل‌ها را دنبال کنید. حتماً دستور زیر را از ترمینال خود اجرا کنید:
    npm install firebase@12.4.0 --save
  2. به صورت دستی به هر دو هسته Firebase و Cloud Functions نیاز دارید:

     import { initializeApp } from 'firebase/app';
     import { getFunctions } from 'firebase/functions';
    
     const app = initializeApp({
         projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
         apiKey: '### FIREBASE API KEY ###',
         authDomain: '### FIREBASE AUTH DOMAIN ###',
       });
     const functions = getFunctions(app);

اندروید

  1. برای افزودن Firebase به برنامه اندروید خود، دستورالعمل‌ها را دنبال کنید.

  2. در فایل Gradle ماژول (سطح برنامه) خود (معمولاً <project>/<app-module>/build.gradle.kts یا <project>/<app-module>/build.gradle )، وابستگی مربوط به کتابخانه Cloud Functions برای اندروید را اضافه کنید. توصیه می‌کنیم برای کنترل نسخه‌بندی کتابخانه Firebase Android BoM استفاده کنید.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:34.4.0"))
    
        // Add the dependency for the Cloud Functions library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-functions")
    }

    با استفاده از Firebase Android BoM ، برنامه شما همیشه از نسخه‌های سازگار کتابخانه‌های اندروید Firebase استفاده خواهد کرد.

    (جایگزین) اضافه کردن وابستگی‌های کتابخانه Firebase بدون استفاده از BoM

    اگر تصمیم به استفاده از Firebase BoM ندارید، باید هر نسخه از کتابخانه Firebase را در خط وابستگی آن مشخص کنید.

    توجه داشته باشید که اگر از چندین کتابخانه Firebase در برنامه خود استفاده می‌کنید، اکیداً توصیه می‌کنیم از BoM برای مدیریت نسخه‌های کتابخانه استفاده کنید، که تضمین می‌کند همه نسخه‌ها سازگار هستند.

    dependencies {
        // Add the dependency for the Cloud Functions library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-functions:22.0.1")
    }

مقداردهی اولیه SDK کلاینت

مقداردهی اولیه یک نمونه از Cloud Functions :

سویفت

lazy var functions = Functions.functions()

هدف-سی

@property(strong, nonatomic) FIRFunctions *functions;
// ...
self.functions = [FIRFunctions functions];

Web

const app = initializeApp({
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
});
const functions = getFunctions(app);

Kotlin

private lateinit var functions: FirebaseFunctions
// ...
functions = Firebase.functions

Java

private FirebaseFunctions mFunctions;
// ...
mFunctions = FirebaseFunctions.getInstance();

تابع را فراخوانی کنید

سویفت

functions.httpsCallable("addMessage").call(["text": inputField.text]) { result, error in
  if let error = error as NSError? {
    if error.domain == FunctionsErrorDomain {
      let code = FunctionsErrorCode(rawValue: error.code)
      let message = error.localizedDescription
      let details = error.userInfo[FunctionsErrorDetailsKey]
    }
    // ...
  }
  if let data = result?.data as? [String: Any], let text = data["text"] as? String {
    self.resultField.text = text
  }
}

هدف-سی

[[_functions HTTPSCallableWithName:@"addMessage"] callWithObject:@{@"text": _inputField.text}
                                                      completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
  if (error) {
    if ([error.domain isEqual:@"com.firebase.functions"]) {
      FIRFunctionsErrorCode code = error.code;
      NSString *message = error.localizedDescription;
      NSObject *details = error.userInfo[@"details"];
    }
    // ...
  }
  self->_resultField.text = result.data[@"text"];
}];

Web

var addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    var sanitizedMessage = result.data.text;
  });

Web

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const sanitizedMessage = data.text;
  });

Kotlin

private fun addMessage(text: String): Task<String> {
    // Create the arguments to the callable function.
    val data = hashMapOf(
        "text" to text,
        "push" to true,
    )

    return functions
        .getHttpsCallable("addMessage")
        .call(data)
        .continueWith { task ->
            // This continuation runs on either success or failure, but if the task
            // has failed then result will throw an Exception which will be
            // propagated down.
            val result = task.result?.data as String
            result
        }
}

Java

private Task<String> addMessage(String text) {
    // Create the arguments to the callable function.
    Map<String, Object> data = new HashMap<>();
    data.put("text", text);
    data.put("push", true);

    return mFunctions
            .getHttpsCallable("addMessage")
            .call(data)
            .continueWith(new Continuation<HttpsCallableResult, String>() {
                @Override
                public String then(@NonNull Task<HttpsCallableResult> task) throws Exception {
                    // This continuation runs on either success or failure, but if the task
                    // has failed then getResult() will throw an Exception which will be
                    // propagated down.
                    String result = (String) task.getResult().getData();
                    return result;
                }
            });
}

Dart

    final result = await FirebaseFunctions.instance.httpsCallable('addMessage').call(
      {
        "text": text,
        "push": true,
      },
    );
    _response = result.data as String;

سی++

firebase::Future<firebase::functions::HttpsCallableResult> AddMessage(
    const std::string& text) {
  // Create the arguments to the callable function.
  firebase::Variant data = firebase::Variant::EmptyMap();
  data.map()["text"] = firebase::Variant(text);
  data.map()["push"] = true;

  // Call the function and add a callback for the result.
  firebase::functions::HttpsCallableReference doSomething =
      functions->GetHttpsCallable("addMessage");
  return doSomething.Call(data);
}

وحدت

private Task<string> addMessage(string text) {
  // Create the arguments to the callable function.
  var data = new Dictionary<string, object>();
  data["text"] = text;
  data["push"] = true;

  // Call the function and extract the operation from the result.
  var function = functions.GetHttpsCallable("addMessage");
  return function.CallAsync(data).ContinueWith((task) => {
    return (string) task.Result.Data;
  });
}

مدیریت خطاها در کلاینت

اگر سرور خطایی ارسال کند یا اگر promise حاصل رد شود، کلاینت خطایی دریافت می‌کند.

اگر خطایی که توسط تابع برگردانده می‌شود از نوع function.https.HttpsError باشد، آنگاه کلاینت code خطا، message و details را از خطای سرور دریافت می‌کند. در غیر این صورت، خطا شامل پیام INTERNAL و کد INTERNAL است. برای نحوه مدیریت خطاها در تابع قابل فراخوانی خود، به راهنمایی مراجعه کنید.

سویفت

if let error = error as NSError? {
  if error.domain == FunctionsErrorDomain {
    let code = FunctionsErrorCode(rawValue: error.code)
    let message = error.localizedDescription
    let details = error.userInfo[FunctionsErrorDetailsKey]
  }
  // ...
}

هدف-سی

if (error) {
  if ([error.domain isEqual:@"com.firebase.functions"]) {
    FIRFunctionsErrorCode code = error.code;
    NSString *message = error.localizedDescription;
    NSObject *details = error.userInfo[@"details"];
  }
  // ...
}

Web

var addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    var sanitizedMessage = result.data.text;
  })
  .catch((error) => {
    // Getting the Error details.
    var code = error.code;
    var message = error.message;
    var details = error.details;
    // ...
  });

Web

import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const sanitizedMessage = data.text;
  })
  .catch((error) => {
    // Getting the Error details.
    const code = error.code;
    const message = error.message;
    const details = error.details;
    // ...
  });

Kotlin

addMessage(inputMessage)
    .addOnCompleteListener { task ->
        if (!task.isSuccessful) {
            val e = task.exception
            if (e is FirebaseFunctionsException) {
                val code = e.code
                val details = e.details
            }
        }
    }

Java

addMessage(inputMessage)
  .addOnCompleteListener(new OnCompleteListener<String>() {
    @Override
    public void onComplete(@NonNull Task<String> task) {
      if (!task.isSuccessful()) {
        Exception e = task.getException();
        if (e instanceof FirebaseFunctionsException) {
          FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
          FirebaseFunctionsException.Code code = ffe.getCode();
          Object details = ffe.getDetails();
        }
      }
    }
  });

Dart

try {
  final result =
      await FirebaseFunctions.instance.httpsCallable('addMessage').call();
} on FirebaseFunctionsException catch (error) {
  print(error.code);
  print(error.details);
  print(error.message);
}

سی++

void OnAddMessageCallback(
    const firebase::Future<firebase::functions::HttpsCallableResult>& future) {
  if (future.error() != firebase::functions::kErrorNone) {
    // Function error code, will be kErrorInternal if the failure was not
    // handled properly in the function call.
    auto code = static_cast<firebase::functions::Error>(future.error());

    // Display the error in the UI.
    DisplayError(code, future.error_message());
    return;
  }

  const firebase::functions::HttpsCallableResult* result = future.result();
  firebase::Variant data = result->data();
  // This will assert if the result returned from the function wasn't a string.
  std::string message = data.string_value();
  // Display the result in the UI.
  DisplayResult(message);
}

// ...

// ...
  auto future = AddMessage(message);
  future.OnCompletion(OnAddMessageCallback);
  // ...

وحدت

 addMessage(text).ContinueWith((task) => {
  if (task.IsFaulted) {
    foreach (var inner in task.Exception.InnerExceptions) {
      if (inner is FunctionsException) {
        var e = (FunctionsException) inner;
        // Function error code, will be INTERNAL if the failure
        // was not handled properly in the function call.
        var code = e.ErrorCode;
        var message = e.ErrorMessage;
      }
    }
  } else {
    string result = task.Result;
  }
});

توصیه شده: با App Check از سوءاستفاده جلوگیری کنید

قبل از اینکه برنامه خود را اجرا کنید، باید App Check فعال کنید تا مطمئن شوید که فقط برنامه‌های شما می‌توانند به نقاط پایانی تابع قابل فراخوانی شما دسترسی داشته باشند.