如何将 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
请求。