如何將 firebase 佇列用作應用程式的後端

Firebase 提供後端即服務,因為 applciation 開發人員無法選擇後端程式碼。

此示例顯示如何使用 firebase 佇列建立後端,該後端將在 firebase 資料庫的頂部執行,並作為前端應用程式的後端。

在進入程式碼之前,讓我們瞭解架構,它將如何工作。為簡潔起見,我們假設我們將網站用作前端,將 NodeJs 伺服器用作後端

先決條件

  1. 使用你的 Google 帳戶建立 firebase 應用程式

  2. 將 firebase 新增到你的網頁。使用 bower install firebase --save

  3. 使用新建立的 firebase 帳戶建立服務帳戶(設定 - >許可權 - >服務帳戶 - >建立服務帳戶 - >(指定名稱並選中提供新的私鑰核取方塊) - >儲存 json 檔案,我們需要那個以後。

  4. 配置可以在你喜歡的環境中託管的 NodeJs 伺服器

  5. queue/specs 中建立以下端點

    “request_response”:

     {
         "error_state": "request_error_processing",
         "finished_state": "finished_state",
         "in_progress_state": "request_in_progress",
         "start_state": "request_started"
     }
    
  6. 在 NodeJs 伺服器內部安裝 firebase 伺服器端版本 npm install firebase --save,並使用我們從步驟 3 獲得的 json 檔案初始化你的服務帳戶,它看起來像這樣

    firebase.initializeApp({serviceAccount:’。/ your_file.json’,databaseURL:‘get_from_firebase_account’});

建築

以下是整個迴圈的工作原理。

在前端,你會做這些步驟

  1. 使用 firebase web sdk,你將請求直接寫入端點’queue / tasks’中的 firebase 資料庫,然後呼叫你要傳送到後端的請求。
  2. 插入任務後,你將在端點 queue/tasks/{taskKey} 上註冊偵聽器,當後端完成處理你的請求時會呼叫該偵聽器,在上面的任務中寫入響應

在後端,你會做這些步驟

  1. 建立無限偵聽端點’佇列/任務’的伺服器
  2. 處理你的任務並在 queue/tasks/response 中寫回響應資料
  3. 刪除任務

首先建立這個輔助函式,它提供了一種處理回撥和承諾的方法

function createPromiseCallback() {
    var cb;
    var promise = new Promise(function (resolve, reject) {
        cb = function (err, data) {
            if (err) return reject(err);
            return resolve(data);
        };
    });
    cb.promise = promise;
    return cb;
}

在前端,你將有這個功能

function sendRequest(kind, params, cb) {

    cb = cb || createPromiseCallback();
    var requestObject = {
        kind: kind,
        params: params
    };
    var tasksRef = firebase.database().ref('queue/tasks');

    var requestKey = tasksRef.push().key;

    var requestRef = tasksRef.child(requestKey);

    function requestHandshake(snap) {
        if (snap && snap.exists() && (snap.val().response || snap.val()._state ===    config.firebase.task.finishState || snap.val()._error_details)) {
            var snapVal = snap.val();
            if (snapVal._error_details) {
                cb(snapVal._error_details.error);
            } else {
            cb(null, snapVal.response);
        }
        requestRef.off('value', requestHandshake);
    }
   }

   var bulkUpdate = {};
   bulkUpdate['queue/tasks/' + requestKey + '/request'] = requestObject;
   bulkUpdate['queue/tasks/' + requestKey + '/_state'] = config.firebase.task.startState;

   firebase.database().ref().update(bulkUpdate)
    .then(function (snap) {
        requestRef.on('value', requestHandshake);
    }).catch(function (err) {
        cb(err);
    });

   return cb.promise;
  }

你可以像 sendRequest('CreateHouseFacade', {houseName:'Test'}) 一樣使用這個功能。

Kind 引數用於後端,知道呼叫處理請求的方法。引數用於傳遞附加引數資訊。

這是後端程式碼

const database = firebase.database();
const queueRef = database.ref('queue');

const queueOptions = {
    'specId': 'request_response',
    'sanitize': false,
    'suppressStack': false,
    'numWorkers': 3
};

function removeTask(task) {
    var taskRef = queueRef.child(`tasks/${task._id}`);
    return taskRef.remove();
}

function processTask(data, progress, resolve, reject) {
    try {
        requestHandler(data.request).then(response => {
            data.response = response || null;
            return resolve(data);
        }).catch(err => {
            return reject(err);
        }).then(snap => {
            removeTask(data);
        });
    } catch (err) {
        reject(err).then(snap => removeTask(data));
    }
}

function requestHandler(request) {
    if (!request || !request.kind) throw new Error('Absent Request or Kind');
    var deferredResponse = requestHandlerFactory(request.kind, request.params);
    return deferredResponse;
}

function requestHandlerFactory(kind, params) {
    // It includes mapping all your backend services
    switch (kind) {
        case 'CreateHouseFacade': return myService(params)
        default: throw new Error(`Invalid kind ${kind} was specified`);
    }
}

函式 myService 包含你的業務邏輯程式碼,它將完成 CreateHouseFacade 請求。