获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

从您的应用调用函数

Cloud Functions for Firebase 客户端 SDK 让您可以直接从 Firebase 应用调用函数。要以这种方式从您的应用程序调用函数,请在 Cloud Functions 中编写和部署一个 HTTPS Callable 函数,然后添加客户端逻辑以从您的应用程序调用该函数。

请务必记住,HTTPS 可调用函数与 HTTP 函数相似但不完全相同。要使用 HTTPS 可调用函数,您必须使用适用于您平台的客户端 SDK 以及functions.https后端 API(或实施协议)。可调用对象与 HTTP 函数有以下主要区别:

  • 对于可调用对象,Firebase 身份验证令牌、FCM 令牌和 App Check 令牌(如果可用)会自动包含在请求中。
  • functions.https.onCall触发器自动反序列化请求主体并验证身份验证令牌。

Firebase SDK for Cloud Functions v0.9.1 及更高版本与这些 Firebase 客户端 SDK 最低版本互操作以支持 HTTPS 可调用函数:

  • 适用于 Apple 平台的 Firebase SDK 10.3.0
  • 适用于 Android 20.2.1 的 Firebase SDK
  • Firebase JavaScript SDK 8.10.1
  • Firebase 模块化 Web SDK 9.0 版

如果您想向在不受支持的平台上构建的应用程序添加类似功能,请参阅https.onCall的协议规范。本指南的其余部分提供有关如何为 Apple 平台、Android、Web、C++ 和 Unity 编写、部署和调用 HTTPS 可调用函数的说明。

编写和部署可调用函数

使用functions.https.onCall创建一个 HTTPS 可调用函数。此方法有两个参数: data和可选的context

// Saves a message to the Firebase Realtime Database but sanitizes the text by removing swearwords.
exports.addMessage = functions.https.onCall((data, context) => {
  // ...
});

例如,对于将文本消息保存到实时数据库的可调用函数, data可以包含消息文本,而context参数表示用户身份验证信息:

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

可调用函数的位置与调用客户端的位置之间的距离会造成网络延迟。要优化性能,请考虑在适用的情况下指定函数位置,并确保在客户端初始化 SDK时将可调用文件的位置与设置的位置对齐。

您可以选择附加 App Check 证明,以帮助保护您的后端资源免遭滥用,例如账单欺诈或网络钓鱼。请参阅为 Cloud Functions 启用 App Check 强制执行

发回结果

要将数据发送回客户端,请返回可以进行 JSON 编码的数据。例如,要返回加法运算的结果:

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

要在异步操作后返回数据,请返回一个承诺。 promise 返回的数据被发送回客户端。例如,您可以返回可调用函数写入实时数据库的经过清理的文本:

// Saving the new message to the Realtime Database.
const sanitizedMessage = sanitizer.sanitizeText(text); // Sanitize the message.
return admin.database().ref('/messages').push({
  text: sanitizedMessage,
  author: { uid, name, picture, email },
}).then(() => {
  console.log('New Message written');
  // Returning the sanitized message to the client.
  return { text: sanitizedMessage };
})

处理错误

为确保客户端获得有用的错误详细信息,通过抛出(或返回被拒绝的 Promise)一个functions.https.HttpsError实例来从可调用对象返回错误。该错误具有code属性,该属性可以是functions.https.HttpsError中列出的值之一。错误还有一个字符串message ,默认为空字符串。他们还可以有一个可选的details字段,该字段具有任意值。如果您的函数抛出HttpsError以外的错误,您的客户端将收到错误消息INTERNAL和代码internal

例如,一个函数可以抛出数据验证和身份验证错误以及错误消息以返回给调用客户端:

// Checking attribute.
if (!(typeof text === 'string') || text.length === 0) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new functions.https.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 (!context.auth) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
      'while authenticated.');
}

部署可调用函数

index.js中保存完成的可调用函数后,它会在您运行firebase deploy时与所有其他函数一起部署。要仅部署可调用对象,请使用所示的--only参数来执行部分部署

firebase deploy --only functions:addMessage

如果您在部署函数时遇到权限错误,请确保将适当的IAM 角色分配给运行部署命令的用户。

设置客户端开发环境

确保您满足任何先决条件,然后将所需的依赖项和客户端库添加到您的应用程序。

iOS+

按照说明将 Firebase 添加到您的 Apple 应用程序

使用 Swift Package Manager 安装和管理 Firebase 依赖项。

  1. 在 Xcode 中,打开您的应用程序项目,导航至File > Add Packages
  2. 出现提示时,添加 Firebase Apple 平台 SDK 存储库:
  3.   https://github.com/firebase/firebase-ios-sdk
  4. 选择 Cloud Functions 库。
  5. 完成后,Xcode 将自动开始在后台解析和下载您的依赖项。

Web version 9

  1. 按照说明将 Firebase 添加到您的 Web 应用程序。确保从终端运行以下命令:
    npm install firebase@9.14.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);
    

Web version 8

  1. 按照说明将 Firebase 添加到您的 Web 应用程序
  2. 将 Firebase 核心和 Cloud Functions 客户端库添加到您的应用程序:
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-functions.js"></script>
    

Cloud Functions SDK 也可以作为 npm 包使用。

  1. 从您的终端运行以下命令:
    npm install firebase@8.10.1 --save
    
  2. 手动需要 Firebase 核心和 Cloud Functions:
    const firebase = require("firebase");
    // Required for side-effects
    require("firebase/functions");
    

Java

  1. 按照说明将 Firebase 添加到您的 Android 应用程序

  2. 在您的模块(应用程序级)Gradle 文件(通常为<project>/<app-module>/build.gradle )中,添加 Cloud Functions Android 库的依赖项。我们建议使用Firebase Android BoM来控制库版本。

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.1.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 Android 库。

    (备选)使用 BoM 的情况下添加 Firebase 库依赖项

    如果您选择不使用 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:20.2.1'
    }
    

Kotlin+KTX

  1. 按照说明将 Firebase 添加到您的 Android 应用程序

  2. 在您的模块(应用程序级)Gradle 文件(通常为<project>/<app-module>/build.gradle )中,添加 Cloud Functions Android 库的依赖项。我们建议使用Firebase Android BoM来控制库版本。

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:31.1.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-ktx'
    }
    

    通过使用Firebase Android BoM ,您的应用将始终使用兼容版本的 Firebase Android 库。

    (备选)使用 BoM 的情况下添加 Firebase 库依赖项

    如果您选择不使用 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-ktx:20.2.1'
    }
    

Dart

  1. 按照说明将 Firebase 添加到您的 Flutter 应用程序

  2. 从 Flutter 项目的根目录,运行以下命令来安装插件:

    flutter pub add cloud_functions
    
  3. 完成后,重建您的 Flutter 应用程序:

    flutter run
    
  4. 安装后,您可以通过在 Dart 代码中导入来访问cloud_functions插件:

    import 'package:cloud_functions/cloud_functions.dart';
    

C++

对于带有 Android 的 C++

  1. 按照说明将 Firebase 添加到您的 C++ 项目
  2. firebase_functions库添加到您的CMakeLists.txt文件中。

对于Apple 平台的 C++

  1. 按照说明将 Firebase 添加到您的 C++ 项目
  2. 将 Cloud Functions pod 添加到您的Podfile
    pod 'Firebase/Functions'
  3. 保存文件,然后运行:
    pod install
  4. Firebase C++ SDK中的 Firebase 核心和 Cloud Functions 框架添加到您的 Xcode 项目中。
    • firebase.framework
    • firebase_functions.framework

统一

  1. 按照说明将 Firebase 添加到您的 Unity 项目
  2. FirebaseFunctions.unitypackage Unity SDK中的 FirebaseFunctions.unitypackage 添加到您的 Unity 项目中。

初始化客户端SDK

初始化 Cloud Functions 的实例:

迅速

lazy var functions = Functions.functions()

目标-C

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

Web version 8

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
  databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
});

// Initialize Cloud Functions through Firebase
var functions = firebase.functions();

Web version 9

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

Java

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

Kotlin+KTX

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

Dart

final functions = FirebaseFunctions.instance;

C++

firebase::functions::Functions* functions;
// ...
functions = firebase::functions::Functions::GetInstance(app);

统一

functions = Firebase.Functions.DefaultInstance;

调用函数

迅速

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

目标-C

[[_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 version 8

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

Web version 9

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;
  });

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;
                }
            });
}

Kotlin+KTX

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

Dart

final result =
    await FirebaseFunctions.instance.httpsCallable('addMessage').call();

C++

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;
  });
}

在客户端处理错误

如果服务器抛出错误或生成的承诺被拒绝,则客户端会收到错误。

如果函数返回的错误是function.https.HttpsError类型,那么客户端会收到服务器错误的错误codemessagedetails 。否则,错误包含消息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]
  }
  // ...
}

目标-C

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

Web version 8

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 version 9

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;
    // ...
  });

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();
                    }
                }
            }
        });

Kotlin+KTX

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

Dart

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

C++

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以帮助确保只有您的应用程序可以访问您的可调用函数端点。