javascript - 使用 Cloud Functions 在 Firestore 数据库上存储来自外部 API 的数据
问题描述
我有一个在 Firebase 上运行的 Vue.js 应用程序,我使用 Firestore 作为数据库。该应用程序必须从另一个应用程序 (app2) 导入数据(客户端),但 app2 仅通过通过 POST 将 XML 代码发送到地址来导出。为了从 app2 接收 POST,我的应用使用了 Firebase Cloud Functions。
const xml2js = require("xml2js");
const functions = require("firebase-functions");
const cors = require("cors");
const express = require("express");
const app = express();
const admin = require("firebase-admin");
const db = admin.initializeApp().firestore();
function parseXml(xml) {
return new Promise((resolve, reject) => {
xml2js.parseString(xml, { explicitArray: false }, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
app.use(cors({ origen: true }));
app.post("/", async (request, response) => {
let xml = request.body.XMLRecords.toString();
const clientes = db.collection("clientes");
xml = xml.replace(/&(?!(?:apos|quot|[gl]t|amp);|#)/g, "&").trim();
xml = " " + xml;
console.log("Prep XML:");
console.log(xml);
let parsXml = await parseXml(xml);
console.log("parsXML");
console.log(parsXml);
Array.from(parsXml.Records.Clientes.Cliente).forEach(async cli => {
if (cli !== null) {
delete cli.$;
const docRef = clientes.doc(cli.CliCodigo);
console.log("cli " + cli.CliCodigo);
console.log(cli);
const writeResult = await docRef.set(cli);
console.log("Cliente " + cli.CliCodigo + " salvo");
}
});
response.send("Received.");
});
exports.apiClientes = functions.https.onRequest((request, response) => {
if (!request.path) {
request.url = `/${request.url}`; // prepend '/' to keep query params if any
}
return app(request, response);
});
该应用程序确实收到了请求并且能够处理它,但是当我尝试与 Firestore 数据库通信时,该函数停止发送console.log()
数据并且不会将数据保存到数据库中。我究竟做错了什么?
解决方案
这很可能是因为在您的Array.from(parsXml.Records.Clientes.Cliente).forEach()
循环中您正在执行几个异步set()
操作,但您在这些异步操作完成之前response.send("Received.");
返回了 response( ) 。
通过这样做response.send("Received.");
,您向运行 Cloud Function 的实例表明它可以终止它,但在大多数情况下,对 Firestore 的异步写入并未完成。
您需要正确处理set()
方法调用返回的 Promises,如下(未经测试):
//....
const promises = [];
Array.from(parsXml.Records.Clientes.Cliente).forEach(cli => {
if (cli !== null) {
delete cli.$;
const docRef = clientes.doc(cli.CliCodigo);
promises.push(docRef.set(cli));
}
});
await Promise.all(promises);
response.send("Received.");
//....
因此,我们使用Promise.all()
并行执行所有set()
方法调用。Promise.all()
方法返回一个单一的Promise,当所有作为可迭代对象(即promises
数组)传递的 Promise 都已实现时,该 Promise 就实现了。因此,当您发回响应时,您确信所有异步工作都已完成,向 Cloud Function 平台表明它可以安全地终止您的 Cloud Function。
推荐阅读
- reactjs - React 选择框中的选项过滤器
- c++ - DEXT 在 macOS 10.15.7 上崩溃
- python-3.x - flickrAPI 上传照片
- c# - c#:如何创建一个空 INT 用作 SQL 参数
- javascript - 如何在javascript中替换字符串的最后一个子字符串?
- .net-core - 我可以从本地化资源中列出所有可用的文化/语言吗?
- postgresql - Qt Postgres'未加载驱动程序'
- javascript - anchor.pathname 在 Chrome 上未定义,在 Firefox 上运行良好
- powershell - 新对象 -ComObject 不一致
- matlab - 如何在 MATLAB 中绘制极坐标函数?