使用 Cloud Functions 在 Firestore 数据库上存储来自外部 API 的数据

Using Cloud Functions to store data form an external API on Firestore database

我在 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()staments 并且不会将数据保存到数据库中。 我做错了什么?

这很可能是因为在您的 Array.from(parsXml.Records.Clientes.Cliente).forEach() 循环中,您正在执行多个异步 set() 操作,但您在那些异步操作之前返回响应 (response.send("Received.");) 操作完成.

通过执行 response.send("Received.");,您向实例 运行 指示您的 Cloud Function 可以终止它,但在大多数情况下,对 Firestore 的异步写入未完成。

您需要正确处理 set() 方法调用返回的 Promise,如下(未测试):

//....
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() 方法 returns 一个 单个 承诺,当所有作为可迭代对象(即 promises 数组)传递给的承诺都已履行时履行。因此,当您发回响应时,您可以确定所有异步工作已完成,向 Cloud Function 平台表明它可以安全地终止您的 Cloud Function。