发出多个 Axios 请求导致 CORS 错误

Posted

技术标签:

【中文标题】发出多个 Axios 请求导致 CORS 错误【英文标题】:Making multiple Axios requests causing CORS errors 【发布时间】: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 无法再次声明。当时不知道那是什么意思,但是,看了你的回答,我现在明白了。 【参考方案1】:

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

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

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

【讨论】:

以上是关于发出多个 Axios 请求导致 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

Axios-一次发出多个请求(vue.js)

由于 CORS 错误,Axios 调用被阻止

发出帖子请求时出现Vuejs axios错误

在 Django 中使用 Axios 和 CORS 获取 POST 请求的错误请求并做出反应

使用 express 配置 CORS 并使用 axios 在前端发出请求

如何使用 Javascript 中的动态链接数组发出多个 Axios 请求?