Skip to content

Latest commit

 

History

History
711 lines (488 loc) · 34.6 KB

File metadata and controls

711 lines (488 loc) · 34.6 KB

七、通过 React 使用 Firebase 云消息传递和云函数

在前几章中,我们探讨了 Firebase 的一些产品,如实时数据库、认证、云 Firestore 和云存储。但是,我们还没有看到一些高级功能,如实时消息和无服务器应用程序开发。现在我们已经准备好探索它们了,所以让我们再讨论一下 Firebase 平台的两个产品:Firebase 云消息和云函数。Firebase Cloud Messaging 是一个跨不同平台发送免费消息的消息平台:Android、iOS 和 web。云函数允许您拥有无服务器应用程序,这意味着您可以在没有服务器的情况下运行自定义应用程序逻辑。

以下是我们将在本章中重点关注的主题列表:

  • Firebase 云消息FCM的关键特性)
  • 为 Javascript Web 应用程序设置 Firebase
  • 客户端应用程序设置以接收通知
  • 要发送通知的服务器安装程序
  • 云函数的关键特性
  • 为云函数设置 Firebase SDK
  • 云函数的生命周期
  • 触发功能
  • 函数的部署和执行
  • 函数的终止

让我们首先从 FCM 开始,然后我们将介绍云函数。

Firebase 云消息传递(FCM)

FCM 提供了一个平台,帮助您使用服务人员实时向应用程序用户发送消息和通知。你每天可以在不同的平台上免费发送数千亿条消息:Android、iOS 和 web(Javascript)。您还可以立即或将来安排邮件传递。

FCM 实现中有两个主要组件:一个可信环境,包括发送消息的应用程序服务器或云函数,以及接收消息的 iOS、Android 或 web(JavaScript)客户端应用程序。

如果你知道谷歌云消息GCM,你可能会问 FCM 与 GCM 有什么不同。这个问题的答案是 FCM 是 GCM 的最新改进版本。它继承了 GCM 的所有基础设施,并对简化的客户端开发进行了改进。请注意,GCM 并没有被弃用,谷歌仍然支持它。然而,新的客户端功能将只提供给 FCM,因此根据 Google 的建议,您应该从 GCM 升级到 FCM。

虽然它支持不同的平台,Android、iOS 和 Web,但在本章中我们将主要讨论 Web(Javascript)。现在让我们看一下 FCM 的主要功能。

FCM 的主要特点

GCM 的主要功能包括下行消息、上行消息和通用消息。让我们在下一节中简要了解这些功能。

发送下游消息

下游消息代表客户端应用程序从服务器发送给用户。FCM 消息可以分为两类:通知消息和数据消息。通知消息直接显示给用户。通知消息的一些示例是警报消息、聊天消息或通知客户端应用程序启动某些处理的消息;让我们来看看备份消息。数据消息需要在客户端应用程序代码中处理。一些示例是聊天信息或特定于您的应用程序的任何信息。我们将在 FCM 消息的下一节中进一步讨论这些消息类型。

发送上行消息

上游消息通过 FCM 通道从设备发送回服务器。您可以通过可靠的 FCM 通道将确认、聊天信息和其他信息从设备发送回服务器。

多功能消息定位

FCM 非常灵活,允许您通过单个设备、一组设备或收听主题的所有订阅者向目标受众发送消息。

FCM 消息

使用 FCM,您可以向客户端发送两种类型的消息:通知消息和数据消息。使用 Firebase SDK 时,这两种消息的最大负载大小均为 4 KB。但是,当您从 Firebase 控制台发送消息时,它强制执行 1024 个字符的限制。

通知消息由 FCM SDK 自动处理,因为它们只是显示消息。当您希望 FCM 代表客户端应用程序显示通知时,可以使用通知消息。通知消息包含预定义的密钥集,也可以包含可选的数据负载。

通知消息对象如下所示:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"This is an FCM notification message!",
      "body":"FCM message"
    }
  }
}

数据消息由客户端应用程序处理,并包含用户定义的密钥。它们如下所示:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Name" : "MT",
      "Education" : "Ph.D."
    }
  }
}

我们将在接下来的部分中看到什么是令牌。

为 Javascript web 应用程序设置 Firebase

FCM 允许您在 service worker 的支持下,在不同浏览器中运行的 web 应用程序中接收通知消息。service worker 是一个在后台运行的浏览器脚本,提供诸如脱机数据功能、后台数据同步、推送通知等功能。服务人员支持在以下浏览器中提供:

  • 铬:50+
  • Firefox:44+
  • Opera Mobile:37+

使用服务工作者,人们可以执行一些恶意活动,例如过滤响应或劫持连接。为了避免这种情况,服务工作者只能在通过 HTTPS 提供服务的页面上使用。因此,如果要使用 FCM,您需要在服务器上提供有效的 SSL 证书。注意,在本地环境中,您不需要 SSL;它在本地主机上工作,没有任何问题。

安装 Firebase 和 Firebase CLI

如果您要开始一个新的 React 项目,最简单的方法是使用 React 初学者工具包。您可以使用以下命令创建 React 项目,然后安装firebasefirebase tools。如果它是现有的 React 和 firebase 项目,您可以跳过安装步骤:

npm install -g create-react-app

您可以使用以下命令安装 Firebase:

npm install firebase --save

您还需要安装 Firebase CLI 才能在服务器上运行项目。可以使用以下命令安装它:

npm install -g firebase-tools

现在,我们将使用 FCM 实现扩展帮助台应用程序。

配置浏览器以接收消息

首先,您需要从添加一个 web 应用程序清单 https://developers.google.com/web/fundamentals/web-app-manifest/file 在我们的项目中,并添加以下内容:

{
  "gcm_sender_id": "103953800507"
}

它告诉浏览器允许 FCM 将消息发送到此应用。103953800507值是硬编码的,在任何应用程序中都必须相同。web 应用程序清单是一个简单的 JSON 文件,将包含与项目相关的配置元数据,例如应用程序的开始 URL 和应用程序图标详细信息。

我们在代码的根文件夹中创建了一个manifest.json文件,并向其中添加了前面的内容。

客户端应用程序设置以接收通知

要允许您的应用程序在浏览器中接收通知,它必须获得用户的权限。为此,我们将添加一段代码,显示一个同意对话框,允许用户授予您的应用程序在浏览器中接收通知的权限。

我们将在主目录下的index.jsx文件中添加componentWillMount()方法,因为我们希望在用户成功登录应用程序后显示对话框:

 componentWillMount() {
      firebase.messaging().requestPermission()
       .then(function() {
        console.log('Permission granted.');
        // you can write logic to get the registration token
          // _this.getToken();
       })
       .catch(function(err) {
        console.log('Unable to get permission to notify.', err);
      });
  }

请注意,您需要使用以下行导入firebase对象:

import firebase from '../firebase/firebase-config';

添加上述代码后,请重新启动服务器并登录应用程序。它应向应用程序的用户显示以下对话框:

一旦用户授予权限,则只有您的浏览器才会收到通知。

现在,让我们编写一个函数来获取注册令牌:

 getToken() {
        console.log("get token");
        firebase.messaging().getToken()
            .then(function (currentToken) {
                if (currentToken) {
                    console.log("current token", currentToken)
                   // sendTokenToServer(currentToken);
                   //updateUI(currentToken);
                } else {
                    // Show permission request.
                    console.log('No Instance ID token available. 
                    Request permission to generate one.');
                    // Show permission UI.
                  // updateUIForPushPermissionRequired();
                   // setTokenSentToServer(false);
                }
            })
            .catch(function (err) {
                console.log('An error occurred while retrieving token. 
                ', err);
              // showToken('Error retrieving Instance ID token. ', 
                 err);
               // setTokenSentToServer(false);
            });
   }

前面的函数将检索需要发送到服务器以订阅通知的当前访问令牌。您可以通过sendTokenToServer()方法实现将该令牌发送到服务器的逻辑。

当您的 web 应用删除注册令牌或用户清除浏览器数据时,注册令牌可能会更改。如果是后者,则需要调用getToken()来检索新令牌。由于注册令牌可能会发生更改,因此还应监视刷新令牌以获取新令牌。每当生成令牌时,FCM 都会触发回调,以便您可以获取新令牌。每当生成新令牌时,onTokenRefresh()回调就会触发,因此在其上下文中调用getToken()方法可以确保您拥有当前注册令牌。您可以编写如下函数:

 refreshToken() {
        firebase.messaging().onTokenRefresh(function () {
            firebase.messaging().getToken()
                .then(function (refreshedToken) {
                    console.log('Token refreshed.');
                    // Indicate that the new Instance ID token has not 
                       yet been sent to the
                    // app server.
                    //setTokenSentToServer(false);
                     Send Instance ID token to app server. Implement it 
                     as per your requirement
                    //sendTokenToServer(refreshedToken);
                    // ...
                })
                .catch(function (err) {
                    console.log('Unable to retrieve refreshed token ', 
                    err);
                    //showToken('Unable to retrieve refreshed token ', 
                      err);
                });
        });
    }

获得令牌后,您可以通过实现类似于sendTokenToServer(refreshedToken)的方法将其发送到应用程序服务器进行存储,如果您使用的是 React 和 Firebase 实时数据库,则可以直接将其存储在数据库中。

所有这些功能都将添加到index.jsx文件中。我们将从componentWillMount()方法调用getToken()函数,而从构造函数调用refreshToken()

现在,在所有这些设置之后,我们将在客户端应用程序中添加接收消息的实际功能。

根据页面状态的不同,无论是在后台运行还是在前台运行(它有焦点),还是关闭或隐藏在选项卡后面,消息的行为都会有所不同。

要接收消息,页面必须处理onMessage()回调,要处理onMessage(),必须在应用程序中定义 Firebase 消息服务工作人员。

我们将在项目的根目录下创建一个名为firebase-messaging-sw.js的文件,并在其中编写以下代码:

importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-messaging.js');

var config = {
    messagingSenderId: "41428255555"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', payload);
    // Customize notification here
    const notificationTitle = 'Background Message Title';
    const notificationOptions = {
        body: 'Background Message body.',
        icon: '/firebase-logo.png'
    };

return self.registration.showNotification(notificationTitle,
    notificationOptions);
});

或者,您可以使用useServiceWorker指定现有的服务人员。

Note that you will need to update the message senderId value, which you can get from the Firebase console for your project.

如果要在网页处于后台时显示通知消息,需要设置setBackgroundMessageHandler来处理消息。您还可以自定义消息,例如设置自定义标题和图标。您可以在前面的代码段中检查它。应用程序处于后台时收到的消息会触发浏览器中的显示通知。

现在您可以处理网页上的OnMessage()事件。我们将在index.js文件中添加一个构造函数,以便它在页面加载时注册回调:

constructor(props) {
        super(props);
        //this.refreshToken();
        firebase.messaging().onMessage(function (payload) {
            console.log("Message received. ", payload);
            // Update the UI to include the received message.
            console.log("msg", payload);
            // appendMessage(payload);
        });
    }

现在,我们的客户端已准备好接收通知消息。让我们配置后端以发送通知。

要发送通知的服务器安装程序

第一步是为您的项目启用 FCMAPI。你可以去https://console.developers.google.com/apis/api/fcm.googleapis.com/overview?project= <项目 id>并启用。

要从受信任的环境发送通知,我们需要一个 Oauth2 访问令牌和客户端应用程序中获得的客户端注册令牌。

要获取 Oauth2 访问令牌,我们需要从您的服务帐户获得私钥。生成私钥后,将包含私钥的 JSON 文件保存在某个安全的位置。我们将使用位于的谷歌 API 客户端库 https://developers.google.com/api-client-library/ 要获取访问令牌,请使用以下命令安装googleapisnpm模块:

npm install googleapis --save

需要将以下功能添加到我们的main.js文件中才能获取访问令牌:

app.get('/getAccessToken', function (req, res) {

  var { google } = require('googleapis');

  var key = require('./firebase/serviceAccountKey.json');
  var jwtClient = new google.auth.JWT(
    key.client_email,
    null,
    key.private_key,
    ['https://www.googleapis.com/auth/firebase.messaging'], // an array 
     of auth scopes
    null
  );
  jwtClient.authorize(function (err, tokens) {
    if (err) {
      console.log(err);
      res.send(JSON.stringify({
        "token": err
      }));
    }
    console.log("tokens", tokens);
    res.send(JSON.stringify({
      "token": tokens.access_token
    }));
  });

});

当您点击http://localhost:3000/getAccessTokenURL 时,它将在浏览器中显示访问令牌。

您将在浏览器中看到如下内容:

显然,在实际应用程序中,出于安全原因,您不会在浏览器中显示此令牌或在浏览器控制台中打印它,而是在内部使用它。

此访问令牌将在请求的Authorization头中传递,如下所示:

headers: {
  'Authorization': 'Bearer ' + accessToken
}

现在您有了访问令牌。另外,如果您还记得的话,我们在设置客户端应用程序时讨论了sendTokenToServer(currentToken)方法,它将令牌发送到服务器。您必须已将其存储在数据库或缓存中,现在可以使用。

现在我们准备好发送第一条通知消息。为了发送消息,我们将使用最新的 HTTP v1send请求。

我们的请求如下所示:

POST https://fcm.googleapis.com/v1/projects/demoproject-7cc0d/messages:send

Content-Type: application/json
Authorization: Bearer ya29.c.ElphBTDpfvg35hKz4nDu9XYn3p1jlTRgw9FD0ubT5h4prOtwC9G9IKslBv8TDaAPohQHY0-O3JmADYfsrk7WWdhZAeOoqWSH4wTsVyijjhE-PWRSL2YI1erT"

{
  "message":{
    "token" : "dWOV8ukFukY:APA91bFIAEkV-9vwAIQNRGt57XX2hl5trWf8YpocOHfkYAkgSZr5wfBsNozYZOEm_N0mbdZmKbvmtVCCWovrng4UYwj-zmpe36ySPcP31HxGGGb3noEkeBFyZRDUpv0TD7HAKxTfDuEx...",
    "notification" : {
      "body" : "This is an FCM notification message!",
      "title" : "FCM Message",
      }
   }
}

您将替换所有令牌并使用项目 ID 更新 URL,然后您应该能够发送第一条消息。

我使用了 rest 客户端发送消息,由于我的浏览器在后台运行,它在系统托盘中显示通知消息。您可以在下一个屏幕截图中看到:

Postman chrome tool extension; the purpose is just to show the request and response of sending the FCM notification message

请求主体如下所示:

Postman chrome tool extension; the purpose of the image is just to show the body of the request that we sent earlier

以下是有关消息请求的重要注意事项:

网址:https://fcm.googleapis.com/v1/projects/<projectid>/messages:send

  • 标题:包含两个键值对:
    • Content-Typeapplication/json
    • AuthorizationBearer<接入令牌>
  • 请求正文:包含具有以下键值的消息对象:
    • token:<客户端 app 向>发送消息的注册令牌
    • notification:包含通知消息的配置

是的,现在我们的应用程序中集成了 FCM,可以将通知消息发送到单个设备,其中应用程序正在后台运行。但是,您可能希望将通知发送到一组设备,或者希望将消息发送到客户端已订阅的主题。基本概念将保持不变,但配置将发生变化。您可以参考 firebase 文档中的这些主题,网址为https://firebase.google.com/docs/cloud-messaging

我们将在下一节中看到云函数。

云函数

通常,任何软件应用程序都有某种后端逻辑,部署在服务器上,以便通过 internet 访问。对于银行或金融等大型企业级应用程序,管理服务器或服务器集群可能是值得的。但是,对于小型应用程序或希望根据某些用户事件(例如数据库中的数据更改或来自移动应用程序或 web 应用程序的 API 请求)执行某些逻辑的应用程序,管理服务器可能是一项工作量和成本方面的开销。但是,当您使用 Firebase 平台时,您无需担心,因为它提供了云函数,允许您根据特定 Firebase 产品发出的事件运行代码,而无需管理服务器。

云函数的关键特性

云函数具有很多功能,包括与其他 Firebase 产品和第三方 API 的轻松集成,以及强大的安全性和隐私性。

云函数的关键特性将在以下子主题中讨论。

与其他 Firebase 产品和第三方 API 无缝集成

云函数可以与其他 Firebase 产品和第三方 API 无缝集成。

您的自定义函数可以在特定事件上执行,这些事件可以由列出的 Firebase 产品发出:

  • 云 Firestore 触发器
  • 实时数据库触发器
  • Firebase 认证触发器
  • Firebase 触发器的谷歌分析
  • 云存储触发器
  • 云发布/订阅触发器
  • HTTP 触发器

您可以使用 Firebase Admin SDK 跨不同的 Firebase 产品进行无缝集成。它在一些最常见的应用程序需求中非常有用。假设您希望在实时数据库中发生更改时生成数据库索引或审核日志;您可以编写基于实时数据库触发器执行的云函数。另一方面,您可以根据特定的用户行为执行一些数据库操作。同样,您也可以将云函数与Firebase 云消息FCM)集成,在数据库中发生特定事件时通知用户。

云函数集成不仅限于 Firebase 产品;您还可以通过编写 Webhook 将云函数与一些第三方 API 服务集成。假设您是开发团队的一员,当有人将代码提交给 Git 时,您希望更新松弛通道。您可以使用 Git Webhook API,它将触发执行逻辑的云函数,将消息发送到 Slack 通道。类似地,您可以使用第三方认证提供程序 API(如 LinkedIn)来允许用户登录。

没有要维护的服务器

云函数运行您的代码,而不需要您购买或维护任何服务器。您可以编写一个 Javascript 或 Typescript 函数,并使用一个命令将其部署到云上。您不需要担心服务器维护或扩展。Firebase 平台将自动为您管理它。服务器实例的扩展是精确的,具体取决于工作负载。

保密

应用程序业务逻辑应该对客户端隐藏,并且必须足够安全,以防止对代码进行任何操纵或反向工程。云函数是完全安全的,因此它始终保持私有,并将始终执行您想要的操作。

函数的生命周期

云函数的生命周期大致可分为五个阶段,分别为:

  1. 您可以为新函数编写代码,并定义执行该函数的条件。函数定义或代码还包含事件提供程序的详细信息,如实时数据库或 FCM。
  2. 使用 Firebase CLI 部署函数,Firebase 将其连接到代码中定义的事件提供程序。
  3. 当事件提供程序生成与函数中定义的条件匹配的事件时,它将被执行。
  4. Google 会根据工作负载自动调整实例数量。
  5. 每当你更新一个函数的代码或删除一个函数时,谷歌将分别自动更新或清理实例。

现在,让我们使用实时数据库提供程序创建一个简单的云函数并进行部署。

为云函数设置 Firebase SDK

必须安装 Firebase CLI 才能进一步初始化云函数。如果尚未安装 Firebase CLI,请按照下一节中的说明进行安装。

Firebase CLI

我们已经在第 5 章用户配置文件和访问管理中看到了如何安装,但下面是命令,仅供参考:

npm install -g firebase-tools

安装 Firebase CLI 后,我们将使用以下命令登录 Firebase 控制台:

firebase login

此命令将打开浏览器 URL 并要求您登录。成功登录后,您可以进入 Firebase 项目的下一步初始化。

初始化 Firebase 云项目

让我们创建一个名为 cloud functions 的空项目目录。我们将从新创建的 cloud-functions 目录中运行以下命令来初始化云函数:

firebase init functions

此命令将引导您完成包含不同步骤的向导,并为您的项目创建必要的文件。它将要求您使用首选语言:Javascript 或 TypeScript。我们将使用此示例的 Typescript。它还将询问您是否要关联任何现有的 firebase 项目,或者是否要创建一个新项目以与之关联。我们将选择一个现有的项目。它还会询问您是否希望它安装所需的节点依赖项。我们将说“是”,以便它安装所有必要的节点包。如果你想自己管理依赖关系,你可以说不。以下屏幕截图显示了向导的外观:

最终结构将如下所示:

让我们了解一些特定于云函数的文件:

  1. firebase.json:包括您项目的属性。它包含一个名为“source”的属性,该属性指向云函数代码的functions文件夹。如果要指向其他文件夹,请在此处进行更改。它还包括一个名为“predeploy”的属性,该属性本质上包含构建和运行代码的命令。
  2. .firebaserc:包含与此目录关联的项目。它可以帮助您在项目之间快速切换。
  3. functions/src/index.ts:这是您所有云函数代码的主要源文件。默认情况下,名为helloworld的函数已经存在于该文件中。但是,默认情况下会将其注释掉。
  4. functions/package.json:包含本项目的 NPM 依赖项。

If you are a  Windows user, you may have to change the value of the property "predeploy" in your firebase.json file from  "npm --prefix  $RESOURCE_DIR run build" to  "npm --prefix %RESOURCE_DIR% run build", as it sometimes gives an error when you try to deploy your function.

一旦安装完成,我们就可以开始部署我们的第一个云函数了。对于这个示例,我们将编写一个简单的函数调用greetUser,它接受request参数中的用户名,并显示一条问候语作为响应:

import * as functions from 'firebase-functions';

export const greetUser = functions.https.onRequest((request, response) => {
        const name = request.query.name;
        response.send("Welcome to Firebase Cloud Function, "+name+"!");
});

首先,我们需要导入 firebase 函数使我们的函数工作。另外,请注意,云函数是通过调用functions.https实现的,这本质上意味着我们正在使用 HTTP 触发器。

greetUser()云函数是一个 HTTP 端点。如果您了解 ExpressJS 编程,您一定注意到该语法类似于 ExpressJS endpoint,当用户点击端点时,它会使用请求和响应对象执行函数。实际上,HTTP 函数的事件处理程序侦听onRequest()事件,该事件支持 Express web framework 管理的路由和应用程序。response 对象用于将响应发送回用户,在我们的示例中是一条文本消息,用户将在浏览器中看到该消息。

云函数的部署和执行

我们需要使用以下命令来部署我们的helloworld云函数:

firebase deploy --only functions

此命令将部署我们的功能,您应该在命令提示符中看到以下响应:

如果部署成功完成,您将看到函数 URL,如https://us-central1-seat-booking.cloudfunctions.net/greetUser,现在可以用来触发云函数的执行。

函数 URL 包括以下内容:

  • us-central1:这是您的功能部署的区域
  • seat-booking:这是 Firebase 项目 ID
  • cloudfunction.net:这是默认域
  • greetUser:部署的功能名称

我们需要附加 passname 属性作为请求参数,以便在问候消息中看到该名称。

当您从浏览器点击该 URL 时,应该会看到以下输出:

所以我们已经成功地创建了一个云函数,耶!

大多数开发人员在将其功能部署到生产或测试环境之前都希望对其功能进行单元测试。您可以使用以下命令在本地部署和测试功能:

firebase serve --only functions

它将启动本地服务器并显示一个 URL,您可以点击该 URL 来测试您的功能:

在本例中,我们看到了如何使用functions.https通过 HTTP 请求触发函数。现在让我们来探索所有触发函数。

触发功能

云函数可以响应其他 Firebase 产品生成的事件而执行,这些事件本质上是云函数的触发器。我们已经在关键特性部分看到了所有触发器的列表。我们将讨论与本书最相关的实时数据库触发器、认证触发器、云存储触发器和云 Firestore 触发器。其余三个可在的 Firebase 文档中查看 https://firebase.google.com/docs/functions/

实时数据库触发器

我们可以创建云函数,它可以响应实时数据库更改以执行某些任务。我们可以使用functions.database为实时数据库事件创建一个新函数。要指定该函数何时执行,我们需要使用一个可用于处理不同数据库事件的事件处理程序。我们还需要指定函数将侦听事件的数据库路径。

*这里给出了云函数支持的事件:

  • onWrite():在实时数据库中创建、销毁或更改数据时触发
  • onCreate():在实时数据库中创建新数据时触发

onUpdate():在实时数据库中更新数据时触发

onDelete():从实时数据库中删除数据时触发

我们可以看到示例实时数据库函数,它侦听数据库中的用户路径,并且,每当任何用户的数据发生任何更改时,它都会将名称转换为大写,并将其设置为用户数据库的同级。在这里,我们使用通配符{userId},它本质上意味着任何userId

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

admin.initializeApp(functions.config().firebase);

export const makeUppercase = functions.database.ref('/users/{userId}')
    .onWrite(event => {
        // Grab the current value of what was written to the Realtime 
           Database.
        const original = event.data.val();
        console.log('Uppercasing', original);
        //status is a property
        const uppercase = original.name.toUpperCase();
        // You must return a Promise when performing asynchronous tasks 
           inside a Functions such as
        // writing to the Firebase Realtime Database.
        // Setting an "uppercase" sibling in the Realtime Database 
           returns a Promise.
        return event.data.ref.parent.child('uppercase').set(uppercase);
});

这里,event.data是一个 DeltaSnapshot。它有一个名为“previous”的属性,可以让您检查在事件发生之前保存到数据库中的内容。previous 属性返回一个新的 DeltaSnapshot,其中所有方法都引用以前的值。

认证触发器

使用认证触发器,我们可以通过 Firebase 认证执行功能代码,以响应用户的创建和删除。

要创建在创建新用户时执行的云函数,我们可以使用以下代码:

exports.userCreated = functions.auth.user().onCreate(event => { ... });

根据 Firebase 文档,云函数的用户创建事件发生在以下场景中:

  • 开发人员使用 Firebase Admin SDK 创建帐户
  • 用户创建电子邮件帐户和密码
  • 用户首次使用联合身份提供程序登录
  • 用户首次登录到新的匿名认证会话

当用户首次使用自定义令牌登录时,不会触发云函数事件。如果要访问新创建用户的属性,可以使用event.data对象。

*例如,您可以按如下方式获取用户的电子邮件和姓名:

const user = event.data; 

const email = user.email;
const name = user.displayName;

除了创建用户外,如果要在用户删除时触发函数,可以使用onDelete()事件处理程序:

exports.deleteUser = functions.auth.user().onDelete(event => {
  // ...
});

云存储触发器

使用云存储触发器,您可以执行 Firebase 云函数来响应云存储中文件和文件夹的创建、更新或删除操作。我们可以使用*functions.Storage 为云存储事件创建一个新函数。*根据需要,您可以拥有监听默认存储桶上所有更改的功能,也可以通过指定存储桶名称将其限制为特定存储桶:

functions.storage.object() - listen for object changes on the default storage bucket.
functions.storage.bucket('test').object() - listen for object changes on a specific bucket called 'test'

例如,我们可以编写一个函数来压缩上载的文件以减小大小:

exports.compressFiles = functions.storage.object().onChange(event => {
  // ...
});

无论何时创建、修改或删除对象,都会触发更改事件。

以下属性由云存储功能公开,可用于进一步处理文件:

  • event.data:表示存储对象。
  • event.data.bucket:存放文件的存储桶。
  • event.data.name:bucket 中的文件路径。
  • event.data.contentType:文件内容类型。
  • event.data.resourceState:两个可能的值:existsnot_exists。如果文件/文件夹已被删除,则设置not_exists值。
  • event.data.metageneration:生成文件元数据的次数;对于新对象,初始值为1

Firebase Cloud 函数最常见的用例是进一步处理文件,例如,压缩文件或生成图像文件的缩略图。

HTTP 触发器

我们已经看到了一个名为greetUser()的 HTTP 端点示例,它涵盖了 HTTP 端点的大部分基本部分。只有一点需要注意,那就是我们应该始终正确地终止我们的功能;否则,它们可能继续运行,系统将强制终止它。我们可以用send()redirect()end()来结束我们的功能。

考虑这个例子:

response.send("Welcome to the Cloud Function");

此外,如果您正在使用 Firebase 托管,并且希望将 HTTP 端点与某个自定义域连接,那么您也可以这样做。

云 Firestore 触发器

使用 Cloud Firestore 触发器,只要函数侦听的指定路径上的数据发生更改,云函数就可以侦听 Cloud Firestore 发出的事件。

在较高的级别上,它的工作方式类似于实时数据库触发器。您可以使用functions.firestore对象收听特定事件。

它支持四个事件:创建、更新、删除和写入,如下所示:

  • onWrite():创建、更新或删除任何文档时触发
  • onCreate():新建单据时触发
  • onUpdate():当已有单据中的任何值发生变化时触发
  • onDelete():删除单据时触发

如果要在特定文档发生更改时执行函数,可以编写如下函数:

exports.updateUser = functions.firestore
  .document('users/{userID}')
  .onWrite(event => {
    // An object with the current document value
    var document = event.data.data();

    // An object with the previous document value (for update or 
       delete)
    var oldDocument = event.data.previous.data();

    // perform desited database operations ...
});

现在我们将讨论云函数终止。

功能终止

云函数的优点是,您不需要自己购买任何服务器,因此您只需要在云函数运行期间支付费用。这也让你有责任正确终止你的函数,不要让你的函数在一个无限循环中运行,否则它会在你的账单中产生额外的费用。

要终止功能并正确管理其生命周期,您可以遵循以下建议方法:

  1. 通过返回 JavaScript 承诺解析异步处理函数
  2. 使用res.redirect()res.send()res.end()结束 HTTP 函数
  3. return;语句结束同步函数

总结

在本章中,我们讨论了 Firebase 的两个高级功能:Firebase 云消息传递和 Firebase 云函数。使用这两个功能,您可以开发一个高度交互式的无服务器应用程序。

FCM 是一个消息传递平台,用于可靠地传递下游和上游消息。我们还讨论了不同的消息类型,并了解了何时使用它们。为了获得 FCM 方面的实际经验,我们增强了帮助台应用程序以发送和接收通知。

我们还讨论了 Firebase 云函数,并了解了无服务器应用程序的帮助。我们介绍了如何开发云函数并将其部署到服务器上。我们还探讨了不同类型的触发器,如实时数据库触发器、HTTP 触发器、云 Firestore 触发器、云存储触发器和认证触发器。

在下一章中,我们将介绍其他高级和有趣的功能,例如 Firebase 云存储和 Firebase 应用程序与 Google 云的集成。**