【问题标题】:Unable to return data from cloud function using https callable无法使用 https 可调用从云函数返回数据
【发布时间】:2020-11-28 12:51:01
【问题描述】:

我正在从我的 Angular 应用程序调用以下云函数,但即使云函数正确记录了结果,返回的值也始终为 null。不知道我做错了什么。

我的 Angular 代码如下:

const data = {test: testToProcess};
const process = this.fns.httpsCallable("gprocess"); // fns is Angular Fire Functions
process(data)
  .toPromise() // since Angular Fire function returns an observable, Iam converting to a promise
  .then(
    (result) => {
      console.log("function called: " + JSON.stringify(result));
    },
    (err) => {
      console.log("Function call error " + JSON.stringify(err));
    }
  );

我的云函数代码如下:

import * as functions from "firebase-functions";
const fs = require("fs");
const { google } = require("googleapis");
const script = google.script("v1");
const scriptId = "MY_SCRIPT_ID";

export const gprocess = functions.https.onCall(async (data: any, context: any) => {
const test = data.test;

return fs.readFile("gapi_credentials.json", (err: any, content: string) => {
  if (err) {return err;}
  const credentials = JSON.parse(content); // load the credentials
  const { client_secret, client_id, redirect_uris } = credentials.web;
  const googleAuth = require("google-auth-library");
  const functionsOauth2Client = new googleAuth.OAuth2Client(client_id, client_secret, redirect_uris); // Constuct an auth client
  functionsOauth2Client.setCredentials({refresh_token: credentials.refresh_token,}); // Authorize a client with credentials
  
  return runScript(functionsOauth2Client,scriptId,JSON.stringify(test))
    .then((scriptData: any) => {
      console.log("Script data in main function is" + JSON.stringify(scriptData));
      return scriptData;
    })
    .catch((error) => {return error;}); 
   });
 });

function runScript(auth: any, scriptid: string, test: any) {
 return new Promise(function (resolve, reject) {
 script.scripts.run({
      auth: auth, 
      scriptId: scriptid,
      resource: {function: "doGet",devMode: true,parameters: test}
    })
  .then((err: any, respons: any) => {
    if (err) {
      console.log("API returned an error: " + JSON.stringify(err));
      resolve(err);
    } else if (respons) {
      console.log("Script is run and response is " + JSON.stringify(respons));
      resolve(respons);
    }
  });
});
}

在云函数上的处理完成之前,角度函数正在返回这个结果。 IT 不等待从云函数返回结果。

detailed.component.ts:691 function called: null

一段时间后,结果会记录在云功能控制台上,但不会返回给 Angular 客户端。云端日志功能如下,正确的结果如下图:

5:53:32.633 PM  gpublish Function execution started
5:53:32.694 PM  gpublish Function execution took 61 ms, finished with status code: 204
5:53:33.185 PM  gpublish Function execution started
5:53:33.804 PM  gpublish Function execution took 620 ms, finished with status code: 200
5:54:31.494 PM  gpublish Script is run and response is : {"config":... some result}
5:54:31.593 PM  gpublish Script data in main function is{"config":... some result}

请帮忙!

【问题讨论】:

    标签: javascript node.js firebase google-cloud-functions angularfire2


    【解决方案1】:

    您的函数未正确返回解析为要序列化并发送给客户端的数据的承诺。问题是 fs.readFile 实际上并没有返回一个承诺。它是异步的,不返回任何内容,这就是客户端将收到的内容。正在调用回调,但回调中的任何内容都不会影响客户端看到的内容。

    您将需要找到另一种方式来执行文件 I/O,该方式要么是同步的(例如 fs.readFileSync),要么实际上与 Pr​​omise 一起工作,而不仅仅是异步回调。

    【讨论】:

    • 我们应该更喜欢 promise-ified fs 方法而不是同步方法吗?我意识到在这种情况下几乎没有什么区别,但我猜你的建议是不要在我们不需要的任何地方阻止服务器。
    • 这完全取决于你。无论哪种方式,您最终都必须等待文件被读取。
    • 很高兴听到。在 Stack Overflow 上,习惯上使用答案左侧的复选标记图标将有用的答案视为正确。
    • 感谢您告诉我。
    【解决方案2】:

    如上所述,我将代码更改为使用 readFileSync(谢谢 Doug!) 此外,我对从云函数发送回 Angular 客户端的数据进行了字符串化处理。

    我的云功能现在看起来像这样:

    import * as functions from "firebase-functions";
    const fs = require("fs");
    const { google } = require("googleapis");
    const script = google.script("v1");
    const scriptId = "MY_SCRIPT_ID";
    
    export const gprocess = functions.https.onCall(
       async (data: any, context: any) => {
       try {
         const test = data.test;
         const content = fs.readFileSync("credentials.json"); // CHANGED TO READFILESYNC
         const credentials = JSON.parse(content); 
         const { client_secret, client_id, redirect_uris } = credentials.web;
      
         const googleAuth = require("google-auth-library");
         const functionsOauth2Client = ... some code to construct an auth client and authorise it
      
        return runScript(functionsOauth2Client,scriptId,JSON.stringify(test)).then((scriptData: any) => {
        return JSON.stringify(scriptData); // STRINGIFIED THE DATA
        });
     } catch (err) {
      return JSON.stringify(err);
     }
    });
    
      function runScript(auth: any, scriptid: string, test: any) {
        return new Promise(function (resolve, reject) {
       
        script.scripts.run({auth: auth,scriptId: scriptid,resource: {function: "doGet",parameters: test}})
         .then((respons: any) => {resolve(respons.data);})
         .catch((error: any) => {reject(error);});
      });
      }
    

    【讨论】:

      猜你喜欢
      • 2020-02-04
      • 2019-11-25
      • 1970-01-01
      • 2021-06-03
      • 2021-03-07
      • 1970-01-01
      • 2020-11-24
      • 2022-10-15
      • 2019-05-10
      相关资源
      最近更新 更多