如何將 firebase 佇列用作應用程式的後端
Firebase 提供後端即服務,因為 applciation 開發人員無法選擇後端程式碼。
此示例顯示如何使用 firebase 佇列建立後端,該後端將在 firebase 資料庫的頂部執行,並作為前端應用程式的後端。
在進入程式碼之前,讓我們瞭解架構,它將如何工作。為簡潔起見,我們假設我們將網站用作前端,將 NodeJs 伺服器用作後端
先決條件
-
使用你的 Google 帳戶建立 firebase 應用程式
-
將 firebase 新增到你的網頁。使用
bower install firebase --save
-
使用新建立的 firebase 帳戶建立服務帳戶(設定 - >許可權 - >服務帳戶 - >建立服務帳戶 - >(指定名稱並選中提供新的私鑰核取方塊) - >儲存 json 檔案,我們需要那個以後。
-
配置可以在你喜歡的環境中託管的 NodeJs 伺服器
-
在
queue/specs
中建立以下端點“request_response”:
{ "error_state": "request_error_processing", "finished_state": "finished_state", "in_progress_state": "request_in_progress", "start_state": "request_started" }
-
在 NodeJs 伺服器內部安裝 firebase 伺服器端版本
npm install firebase --save
,並使用我們從步驟 3 獲得的 json 檔案初始化你的服務帳戶,它看起來像這樣firebase.initializeApp({serviceAccount:’。/ your_file.json’,databaseURL:‘get_from_firebase_account’});
建築
以下是整個迴圈的工作原理。
在前端,你會做這些步驟
- 使用 firebase web sdk,你將請求直接寫入端點’queue / tasks’中的 firebase 資料庫,然後呼叫你要傳送到後端的請求。
- 插入任務後,你將在端點
queue/tasks/{taskKey}
上註冊偵聽器,當後端完成處理你的請求時會呼叫該偵聽器,在上面的任務中寫入響應
在後端,你會做這些步驟
- 建立無限偵聽端點’佇列/任務’的伺服器
- 處理你的任務並在
queue/tasks/response
中寫回響應資料 - 刪除任務
首先建立這個輔助函式,它提供了一種處理回撥和承諾的方法
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
請求。