【问题标题】:Making multiple Axios requests causing CORS errors发出多个 Axios 请求导致 CORS 错误
【发布时间】:2020-03-04 09:38:24
【问题描述】:

我使用 Axios 从前端向 Firebase Functions 后端发出 HTTP POST 请求。我希望能够同时发送两个请求来调用两个函数,createEmaileListzohoCrmHook。问题是,当我同时向这两个函数发出请求时,它给了我 CORS 错误。当我向单个功能提出请求时,它们工作得很好。如何同时向多个函数发出请求?

下面是前端:

const handleSubmit = e => {
    setLoading(true)                
    e.preventDefault()  
    axios.all([
        axios.post(`${ROOT_URL}/createEmailList`, {
            email,
            firstName,
            lastName
        }),
        axios.post(`${ROOT_URL}/zohoCrmHook`, {
            email,
            firstName,
            lastName
        })
    ])
    .then(axios.spread((emailRes, crmRes) => { 
        if(emailRes.status===200 || emailRes.status===204 || crmRes.status===200 || crmRes.status===204 || crmRes.status===201){
            setLoading(false)
            closeModal()
        } 
    }))
    .catch(err=> console.log(err));
}

后台index.js如下:

const functions = require('firebase-functions');
const admin = require("firebase-admin")
const serviceAccount = require("./service_account.json");
const createEmailList = require('./createEmailList')
const zohoCrmHook = require('./zohoCrmHook')

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://landing-page.firebaseio.com"
})

exports.zohoCrmHook = functions.https.onRequest(zohoCrmHook)
exports.createEmailList = functions.https.onRequest(createEmailList)

我已经导入了cors 模块并实现了如下功能,但它仍然只能单独工作,不能同时工作

createEmailList.js

const admin = require('firebase-admin')
const cors = require('cors')({ origin: true })

module.exports = (req, res) => {
    cors(req, res, () => {
        if (!req.body.email) {
            return res.status(422).send({ error: 'Bad Input'})
        }

        const email = String(req.body.email)
        const firstName = String(req.body.firstName)
        const lastName = String(req.body.lastName)

        const data = {
            email,
            firstName,
            lastName    
        }

        const db = admin.firestore()
        const docRef = db.collection('users')
            .doc(email)
            .set(data, { merge: false })
            .catch(err => res.status(422).send({ error: err }))

        return res.status(204).end();    
    })
}

zohoCrmHook.js

const axios = require('axios');
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true })

// zoho
const clientId = functions.config().zoho.client_id;
const clientSecret = functions.config().zoho.client_secret;
const refreshToken = functions.config().zoho.refresh_token;
const baseURL = 'https://accounts.zoho.com';

module.exports = (req, res) => {
    cors(req, res, async () => {        
        const newLead = {
            'data': [
            {
                'Email': String(req.body.email),
                'Last_Name': String(req.body.lastName),
                'First_Name': String(req.body.firstName),
            }
            ],
            'trigger': [
                'approval',
                'workflow',
                'blueprint'
            ]
        };

        const { data } = await getAccessToken();
        const accessToken = data.access_token;

        const leads = await getLeads(accessToken);
        const result = checkLeads(leads.data.data, newLead.data[0].Email);

        if (result.length < 1) {
            try {
                return res.json(await createLead(accessToken, newLead));
            } catch (e) {
                console.log("createLead error", e);
            }
        } else {
            return res.json({ message: 'Lead already in CRM' })
        }
    })
}

更新
我还尝试将这两个 Firebase 函数合二为一,如下所示:

exports.myWebHook = functions.https.onRequest(async (req, res) => {
  createEmailList(req, res)
  zohoCrmHook(req, res)
})

并将前端axios 请求合二为一:

const handleSubmit = e => {
        setLoading(true)                
        e.preventDefault()  

        axios.post(`${ROOT_URL}/myWebHook`, {
            email,
            firstName,
            lastName
        })
        .then(res => { 
            if(res.status===200 || res.status===204){
                setLoading(false)
                closeModal()
            } 
        })
        .catch(err=> console.log(err));
    }

但是,它仍然给出相同的 CORS 错误:

访问 XMLHttpRequest 在 'https://us-landing-page.cloudfunctions.net/myWebHook' 来自原点 'https://www.website.com' 已被 CORS 阻止 策略:对预检请求的响应未通过访问控制 检查:预检请求不允许重定向。

更新2
我尝试将 CORS 模块合并到 index.js 中,如下所示,并从这两个函数中删除了 CORS 模块。

exports.myWebHook = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {            
    zohoCrmHook(req, res)  
    createEmailList(req, res)
  })
})

现在,对服务器的axios 请求不会引发任何CORS 错误,并且myWebHook 函数被调用没有问题,但zohoCrmHookcreateEmailList 函数都没有被调用。

【问题讨论】:

  • 实际上不知道 Firebase,但两次导入 CORS 并设置其值看起来很可疑。我觉得 CORS 应该初始化一次,然后只添加资源。我知道在堆栈中设置多个 CORS 标头会引发错误的问题。不确定这里是否正是这种情况,但可能值得一试。
  • 如果我要从任何一个函数中删除 CORS 模块,则表明进程已被 CORS 策略阻止的错误只是指向该特定函数。
  • 听起来更好,您可以不在入口点设置 cors 并导入您的函数并将它们作为资源添加到同一个 cors 实例吗?
  • 我已经尝试了你的建议并通过答案更新了,但仍然不行
  • 当我尝试应用 CORS 模块的不同变体时,我也曾一度收到错误消息,指出已声明的 Header 无法再次声明。当时不知道那是什么意思,但是,看了你的回答,我现在明白了。

标签: javascript node.js firebase cors axios


【解决方案1】:

如果我们查看代码,我们会看到 CORS 不仅被导入,而且还被选项对象调用。所以我认为它两次实例化 CORS 并多次设置相同的 CORS 标头,这会导致问题。

const cors = require('cors')({ origin: true })

我的建议是,在入口点实例化一次 CORS,并将函数作为资源添加到同一个 CORS 实例。

【讨论】:

    猜你喜欢
    • 2019-11-10
    • 2021-03-31
    • 2022-01-23
    • 1970-01-01
    • 2022-01-06
    • 2018-10-24
    • 2020-05-08
    • 2020-04-03
    • 2020-03-08
    相关资源
    最近更新 更多