如果我在我的 firebase 云功能中将请求的模式设置为“no-cors”,会发生啥?

Posted

技术标签:

【中文标题】如果我在我的 firebase 云功能中将请求的模式设置为“no-cors”,会发生啥?【英文标题】:What will happen if I set the request's mode to 'no-cors' in my firebase cloud function?如果我在我的 firebase 云功能中将请求的模式设置为“no-cors”,会发生什么? 【发布时间】:2020-04-11 01:11:49 【问题描述】:

这是对this 问题的跟进。我有一个 firebase 功能,它应该接受 OTP,对其进行验证,然后根据它是否正确更改用户的密码(由于某种原因,我无法使用 firebase 的内置密码重置功能)。以下是我的功能:

exports.resetPassword = functions.https.onCall((data, context) => 
    return new Promise((resolve, reject) => 
        if(data.sesId && data.otp)
            admin.firestore().collection('verification').doc(data.sesId).get().then(verSnp => 
                if(verSnp.data().attempt != 'verified')
                    var now = new Date().getTime()
                    if(verSnp.data().expiring > now)
                        if(data.email == verSnp.data().email)
                            if(verSnp.data().attempt > 0)
                                if(data.otp == verSnp.data().otp)
                                    admin.auth().getUserByEmail(data.email).then(user => 
                                        admin.auth().updateUser(user.uid,
                                            password: data.password
                                        ).then(() => 
                                            admin.firestore().collection('verification').doc(data.sesId).update(
                                                attempt: 'verified'
                                            ).then(() => 
                                                Promise.resolve()
                                            ).catch(() => 
                                                throw new Error('Error updating the database.')
                                            )
                                        ).catch(() => 
                                            throw new Error('Error updating the password. Please try again.')
                                        )
                                    ).catch(() => 
                                        throw new Error('Incorrect email. How did you get here?')
                                    )
                                 else 
                                    var redAttempt = verSnp.data().attempt - 1
                                    admin.firestore().collection('verification').doc(data.sesId).update(
                                        attempt: redAttempt
                                    ).then(() => 
                                        throw new Error(`Incorrect OTP. You have $redAttempt attempts remaining.`)
                                    ).catch(() => 
                                        throw new Error('Wrong OTP, try again.')
                                    )
                                
                             else 
                                throw new Error('Incorrect OTP. You have exhausted your attempts. Please request a new OTP.')
                            
                         else 
                            throw new Error('Incorrect email. How did you get here?')
                        
                     else 
                        throw new Error('OTP is expired. Please request a new OTP.')
                    
                 else 
                    throw new Error('OTP is invalid. Please request a new OTP.')
                
            ).catch(() => 
                throw new Error('Invalid session id. Please request the OTP through Forgot Password.')
            )
         else 
            throw new Error('Enter OTP')
        
    )
)

当我运行该函数时,它会被执行,因为我可以在控制台语句中看到它,但是我的客户端出现以下错误。

Access to fetch at 'https://us-central1-project-name.cloudfunctions.net/functionName' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

当我记录从函数收到的响应时,它显示"code":"internal"

什么是 cors 包?我该如何解决这个问题?


第 2 部分(不相关)

另外,在我的函数的第 11 行和第 12 行,我正在使用

admin.auth().getUserByEmail(data.email).then(user => 
  admin.auth().updateUser(user.uid, password: data.password)
)

这对吗?


对于第 1 部分,我提到了this 问题,但没有答案。

【问题讨论】:

【参考方案1】:

查看可调用云函数的 documentation:

    不需要将其封装在return new Promise((resolve, reject) => )中; 您需要返回可以 JSON 编码的数据; 您需要正确管理错误,方法是抛出(或返回被拒绝的 Promise)functions.https.HttpsError 的实例; 您需要正确链接异步方法返回的所有承诺。

我已尝试在下面根据上述几点重新组织您的代码,但由于您的业务逻辑很复杂,我无法对其进行测试,并且可能有其他方法来管理所有案例...由您决定来“打磨”这第一次尝试!希望它会有所帮助。

exports.resetPassword = functions.https.onCall((data, context) => 

        if(data.sesId && data.otp)

            let dataOptCorresponds = true;

            return admin.firestore().collection('verification').doc(data.sesId).get()
            .then(verSnp => 
                if(verSnp.data().attempt != 'verified')

                    var now = new Date().getTime()

                    if(verSnp.data().expiring > now)
                        if(data.email == verSnp.data().email)
                            if(verSnp.data().attempt > 0)
                                if(data.otp == verSnp.data().otp)
                                    return admin.auth().getUserByEmail(data.email);
                                 else 
                                    dataOptCorresponds = false;
                                    var redAttempt = verSnp.data().attempt - 1
                                    return admin.firestore().collection('verification').doc(data.sesId).update(
                                        attempt: redAttempt
                                    )
                                
                             else 
                                throw new Error('Incorrect OTP. You have exhausted your attempts. Please request a new OTP.')
                            
                         else 
                            throw new Error('Incorrect email. How did you get here?')
                        
                     else 
                        throw new Error('OTP is expired. Please request a new OTP.')
                    
                 else 
                    throw new Error('OTP is invalid. Please request a new OTP.')
                
            )
            .then(user => 
                if(dataOptCorresponds) 
                    return admin.auth().updateUser(user.uid,
                        password: data.password
                    )
                 else 
                    throw new Error(`Incorrect OTP. You have xxxx attempts remaining.`)
                
            )
            .then(() => 
                return admin.firestore().collection('verification').doc(data.sesId).update(
                    attempt: 'verified'
                )
            .then(() => 
                return result: "success"                      
            )          
            .catch(error => 
                throw new functions.https.HttpsError('internal', error.message);

            )

         else 

            throw new functions.https.HttpsError('invalid-argument', 'Enter OTP');
        

)

更新以下 Bergi 的评论:

如果您希望能够区分返回到前端的错误类型(特别是在 OTP 不正确、无效或过期或电子邮件不正确的情况下发回 invalid-argument HttpsError),您可以在then() 方法中使用第二个参数。

exports.resetPassword = functions.https.onCall((data, context) => 

        if(data.sesId && data.otp)

            let dataOptCorresponds = true;

            return admin.firestore().collection('verification').doc(data.sesId).get()
            .then(

                verSnp => 
                    if(verSnp.data().attempt != 'verified')

                        var now = new Date().getTime()

                        if(verSnp.data().expiring > now)
                            if(data.email == verSnp.data().email)
                                if(verSnp.data().attempt > 0)
                                    if(data.otp == verSnp.data().otp)
                                        return admin.auth().getUserByEmail(data.email);
                                     else 
                                        dataOptCorresponds = false;
                                        var redAttempt = verSnp.data().attempt - 1
                                        return admin.firestore().collection('verification').doc(data.sesId).update(
                                            attempt: redAttempt
                                        )
                                    
                                 else 
                                    throw new Error('Incorrect OTP. You have exhausted your attempts. Please request a new OTP.')
                                
                             else 
                                throw new Error('Incorrect email. How did you get here?')
                            
                         else 
                            throw new Error('OTP is expired. Please request a new OTP.')
                        
                     else 
                        throw new Error('OTP is invalid. Please request a new OTP.')
                    
                ,

                error => 

                    throw new functions.https.HttpsError('invalid-argument', error.message);

                

            )
            .then(user => 
                if(dataOptCorresponds) 
                    return admin.auth().updateUser(user.uid,
                        password: data.password
                    )
                 else 
                    throw new Error(`Incorrect OTP. You have xxxx attempts remaining.`)
                
            )
            .then(() => 
                return admin.firestore().collection('verification').doc(data.sesId).update(
                    attempt: 'verified'
                )
            .then(() => 
                return result: "success"                      
            )          
            .catch(error => 
                throw new functions.https.HttpsError('internal', error.message);

            )

         else 

            throw new functions.https.HttpsError('invalid-argument', 'Enter OTP');
        

)

【讨论】:

最后加上.catch(),所有thrown 错误最终都成为内部HttpsError。您需要将其向上移动或use the second then parameter。 @Bergi 感谢您的“提示”!我试图调整答案。如果您可以查看并确认这是正确的方法,那就太好了!但是,我看不到如何在我们有 if(dataOptCorresponds) 的地方实现第二个 then() 参数,因为错误是 dataOptCorresponds 值的函数... 哎呀,忘了我在说什么。我没有正确阅读您的答案,也没有意识到您实际上希望将所有错误消息都包含在HttpsError 中。我猜你原来的方法是正确的。 伙计们,我非常感谢您的帮助,但由于假期,我已经有一周不在办公桌前了。一旦有机会试用代码,我会尽快回复。 @VaibhavJoshi 为什么不使用batched write 来更新 3 个不同集合中的多个文档?

以上是关于如果我在我的 firebase 云功能中将请求的模式设置为“no-cors”,会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

Firebase云功能:如何处理持续请求

如何在我的java类中将firebase值存储为全局整数[重复]

Firebase 云功能直接应用程序调用客户端

Firebase 云功能总是超时

为 Firebase 云功能启用 Cors

Puppeteer 等待页面和 setTimeout 在 Firebase 云功能中不起作用