在 Cloud Functions 中使用 Cloud Firestore 数据

Posted

技术标签:

【中文标题】在 Cloud Functions 中使用 Cloud Firestore 数据【英文标题】:Using Cloud Firestore data in a Cloud Function 【发布时间】:2021-03-29 05:56:13 【问题描述】:

我正在尝试创建从 Cloud Firestore 获取数据的 Cloud Functions,并使用从 Cloud Firestore 获取的值向支付网关 API 发送支付请求。

我可以使用这个函数从 Firestore 中获取我需要的文档:

exports.getData = functions.https.onRequest((req, res) => 
  const docRef = db.collection('requests').doc('vsFyJ5lisBgYNwQEzOLa');
  const getDoc = docRef.get()
    .then(doc => 
      if (!doc.exists) 
        console.log('No such document!');
        return res.send('Not Found')
       
        console.log(doc.data());
        return res.send(doc.data());
    )
    .catch(err => 
      console.log('Error getting document', err);
      
    );
    
 );

但是,这个函数只打印文档值;我需要在另一个函数中使用这些值,如下所示:

exports.pay = functions.https.onRequest((req, res) => 
  var Iyzipay = require('iyzipay');
  const doc = db.collection('requests').doc('vsFyJ5lisBgYNwQEzOLa');
  const iyzipay = new Iyzipay(
    apiKey: 'apiKey',
    secretKey: 'secretKey',
      uri: 'https://sandbox-api.iyzipay.com'
  );
  var request = 
    locale: Iyzipay.LOCALE.TR,
    conversationId: '123456789',
    price: doc.price,
    paidPrice: doc.paidPrice,
    currency: Iyzipay.CURRENCY.TRY,
    installment: '1',
    basketId: 'B67832',
    paymentChannel: Iyzipay.PAYMENT_CHANNEL.WEB,
    paymentGroup: Iyzipay.PAYMENT_GROUP.PRODUCT,
    paymentCard: 
        cardHolderName: doc.cardHolderName,
        cardNumber: doc.cardNumber,
        expireMonth: doc.expireMonth,
        expireYear: doc.expireYear,
        cvc: doc.cvc,
        registerCard: '0'
    ,
  ;
iyzipay.payment.create(request, function (err, result) 
  console.log(err, result);
);
);

我尝试组合如下功能:

exports.pay = functions.https.onRequest((req, res) => 
  var Iyzipay = require('iyzipay');
  const doc = db.collection('requests').doc('vsFyJ5lisBgYNwQEzOLa');
  const iyzipay = new Iyzipay(
    apiKey: 'sandbox-afXhZPW0MQlE4dCUUlHcEopnMBgXnAZI',
    secretKey: 'sandbox-wbwpzKIiplZxI3hh5ALI4FJyAcZKL6kq',
      uri: 'https://sandbox-api.iyzipay.com'
  );
  const docRef = db.collection('requests').doc('vsFyJ5lisBgYNwQEzOLa');
  const getDoc = docRef.get()
    .then(doc => 
      if (!doc.exists) 
        console.log('No such document!');
        return res.send('Not Found')
       
        console.log(doc.data());
        return res.send(doc.data());
    )
    .catch(err => 
      console.log('Error getting document', err);
      
    );
  var request = 
    locale: Iyzipay.LOCALE.TR,
    conversationId: '123456789',
    price: '1',
    paidPrice: '1.2',
    currency: Iyzipay.CURRENCY.TRY,
    installment: '1',
    basketId: 'B67832',
    paymentChannel: Iyzipay.PAYMENT_CHANNEL.WEB,
    paymentGroup: Iyzipay.PAYMENT_GROUP.PRODUCT,
    paymentCard: 
        cardHolderName: doc.cardHolderName,
        cardNumber: doc.cardNumber,
        expireMonth: doc.expireMonth,
        expireYear: doc.expireYear,
        cvc: doc.cvc,
        registerCard: '0'
            
  ;
iyzipay.payment.create(request, function (err, result) 
  console.log(err, result);
);
);

当 Firestore 查询像以前一样打印在控制台上时,支付处理器返回错误。

然后我尝试使用如下静态值调用支付处理器:

var request = 
    locale: Iyzipay.LOCALE.TR,
    conversationId: '123456789',
    price: '1',
    paidPrice: '1.2',
    currency: Iyzipay.CURRENCY.TRY,
    installment: '1',
    basketId: 'B67832',
    paymentChannel: Iyzipay.PAYMENT_CHANNEL.WEB,
    paymentGroup: Iyzipay.PAYMENT_GROUP.LISTING,
    paymentCard: 
        cardHolderName: 'John Doe',
        cardNumber: '5528790000000008',
        expireMonth: '12',
        expireYear: '2030',
        cvc: '123',
        registerCard: '0'


支付处理器返回成功,所以我获取或使用 Firestore 文档值的方式一定有问题。

为了再次测试它是否确实使用了 Firestore 值,我只将一个字段切换为 cardNumber: doc.cardNumber。控制台返回:

✔  functions[pay]: http function initialized (http://localhost:5000/highmidlow1/us-central1/pay).
i  functions: Beginning execution of "pay"
⚠  External network resource requested!
   - URL: "https://sandbox-api.iyzipay.com/payment/auth"
 - Be careful, this may be a production service.
⚠  Google API requested!
   - URL: "https://oauth2.googleapis.com/token"
   - Be careful, this may be a production service.
>  null 
>    status: 'failure',
>    errorCode: '12',
>    errorMessage: 'Invalid card number',
>    locale: 'tr',
>    systemTime: 1608311421424,
>    conversationId: '123456789'
>  
>  
>    expireYear: '2030',
>    paidPrice: 1.2,
>    cardNumber: '5528790000000008',
>    cvc: '123',
>    price: 1,
>    expireMonth: '12',  

那么如何从 Firestore 中获取文档并在 Cloud Function 中使用其值,例如 price: doc.price

【问题讨论】:

似乎您只需要将第一个函数中的查询与第二个函数中对支付处理器的调用结合起来。你具体有什么问题?请编辑问题以明确。 嗨@DougStevenson,感谢您的快速回复。当我结合这两个函数时,支付处理器返回一个错误,而 Firestore 查询在控制台上打印值。当我尝试使用价格:'1'而不是价格:doc.price 等值调用支付处理器时,它返回成功。因此,我认为获取和使用 Firestore 文档值的方式一定有问题。 您的 Firestore 可能将 doc.price 作为 字符串,而支付处理器需要它作为数字。其他常见问题通常归结为某种格式 - “1”、“$1”、“1.00”、1、1.00、“USD 1.00”都是信息可能保存在数据库中的所有可能方式。 如果有错误消息,您应该将其与调试详细信息一起显示出来,以便我们跟踪问题所在。 @LeadDreamer,感谢您的回复。我也想到了这一点,我从处理器的文档中检查了格式是否正确。他们似乎是正确的,所以我认为这是关于别的事情。 【参考方案1】:

我认为您需要将您的请求逻辑移动到 .then(...) 块中,因为现在看起来您正试图在实际返回的块之外使用文档结果,这可能就是您为什么收到“无效卡号”错误。

Firestore API 将 Promises 用于大多数/所有 fetch 操作,因此您始终需要等待结果才能使用它。

// ...
docRef.get().then(doc => 
    if (!doc.exists) 
        console.log('No such document!');
        return res.send('Not Found')
    
    console.log(doc.data());
    res.send(doc.data());

    const request =  ... 
)

如果您使用支持async/await 的节点版本,则可能更容易发现这些类型的错误。

const doc = await docRef.get()
if (!doc.exists) 
    console.log('No such document!');
    return res.send('Not Found')

console.log(doc.data());
res.send(doc.data());

const request =  ... 

【讨论】:

感谢您的回复。我觉得这应该可行,但是当我使用异步时,我收到“语法错误:等待仅在异步函数中有效”。要解决这个问题,我应该使用 async function pay() 之类的东西来使其成为异步函数吗?如果是这样,我应该在哪里开始和结束异步功能? 我还根据您的第一个建议修复了代码,没有异步,将请求移到返回文档的块内,但仍然给出相同的无效卡号错误。 关于您的第一个问题,是的,您需要在使用await 的任何时候在封闭函数前面添加async,在您的情况下,这是传递给的匿名回调云函数api。所以它将是functions.https.onRequest(async (req, res) => ... )。用async 关键字标记的函数无论如何都保证返回一个Promise,这可以简化调用者的结果/错误处理。至于开始/结束,我会让整个 Cloud Function 处理程序异步并在每个返回承诺的调用之前使用await 至于失败,能否将新的失败代码添加到您的问题中? 我设法在没有异步的情况下解决了它,但我一定会在以后实现它。您的第一个建议是解决方案的重要组成部分,除了我必须将价格:doc.price 更改为价格:doc.data(doc).price,突然它起作用了!谢谢。

以上是关于在 Cloud Functions 中使用 Cloud Firestore 数据的主要内容,如果未能解决你的问题,请参考以下文章

spring-cloud-alibaba-sentinel和feign配合使用,启动报Caused by: java.lang.AbstractMethodError: com.alibaba.clo

如何在 Angular 组件中正确使用 Cloud Functions?

IBM Cloud Functions:在 Nodejs 中使用异步调用

如何使用 Google Python Client for Cloud Functions 获取 Google Cloud Functions 列表?

在 JS 中使用 Cloud Functions 将数据设置到 Firestore

在 Firebase Cloud Functions 中使用 express 和 consign 进行路由