You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Async Axios请求未满足条件即执行:POST提前于GET运行问题

问题分析与解决:HubSpot接口调用顺序异常导致更新逻辑失效

问题场景

我有一个接收user对象的异步函数,逻辑是:

  1. 调用HubSpot的GET接口获取用户现有数据
  2. 对比返回数据与传入的updatedUser,若不匹配则调用POST接口更新记录

但实际运行时,当传入对象与HubSpot原有记录不匹配时,POST请求似乎在GET请求完成前就执行了,导致GET拿到的是已经更新后的数据,if (!_.isEqual(hubspotData, updatedUser))分支的日志不打印,最终走了else分支。

代码示例

async function updateContactDetails(updatedUser) {
    const token = await verifyToken();
    let hubspotData;
    // 获取现有记录
    try {
        if (!token) throw new Error('Hubspot api token not found.');
        const getUrl = `https://api.hubapi.com/contacts/v1/contact/email/${updatedUser.email}/profile`;
        const response = await axios.get(getUrl, {
            headers: {
                Authorization: `Bearer ${token}`,
            },
        });
        hubspotData = {
            firstname: response.data.properties?.firstname?.value,
            lastname: response.data.properties?.lastname?.value,
            email: response.data.properties?.email?.value,
        };
        console.log('🚀 ~ updateContactDetails ~ updatedUser:', updatedUser);
        console.log('🚀 ~ updateContactDetails ~ hubspotData:', hubspotData);
    } catch (e) {
        console.log('Hubspot API - fetch error:', e?.response?.data || e);
    }
    // 对比后更新
    if (!_.isEqual(hubspotData, updatedUser)) {
        console.log("not equal - making post request")
        try {
            console.log('🚀 ~ updateContactDetails ~ updating');
            const updateUrl = `https://api.hubapi.com/contacts/v1/contact/createOrUpdate/email/${updatedUser.email}`;
            const response = await axios.post(
                updateUrl,
                {
                    properties: [
                        {
                            property: 'firstname',
                            value: updatedUser.firstname,
                        },
                        {
                            property: 'lastname',
                            value: updatedUser.lastname,
                        },
                        {
                            property: 'email',
                            value: updatedUser.email,
                        },
                    ],
                },
                {
                    headers: {
                        Authorization: `Bearer ${token}`,
                    },
                }
            );
            const action = response.data.isNew ? 'create' : 'update';
            console.log(`Contact ${action}d with ${response.config.data}`);
        } catch (e) {
            console.log('Hubspot API - create/update error:', e?.response?.data || e);
        }
    } else {
        console.log('Hubspot contact matches user input');
    }
}

控制台输出(异常情况)

传入firstname为Test6的updatedUser,HubSpot原有记录的firstname应为Test2,但输出显示:

🚀 ~ updateContactDetails ~ updatedUser: {
  firstname: 'Test6',
  lastname: 'Test2',
  email: <email>,
}
🚀 ~ updateContactDetails ~ hubspotData: {
  firstname: 'Test6',
  lastname: 'Test2',
  email: <email>,
}
Hubspot contact matches user input

排查过程

  • 尝试将所有代码放入同一个try/catch、移除所有try/catch、简化对比逻辑、抽象接口调用为独立函数,均无效。
  • 注释POST请求代码后,对比逻辑正常触发,说明对比逻辑本身无问题;恢复POST后,更新操作立即执行,导致GET拿到更新后的数据。

核心原因

最可能的情况是函数被重复并发调用:同一个updatedUser(或同一email)触发了多次updateContactDetails调用,第一次调用的POST还在执行时,第二次调用的GET已经发起,此时HubSpot的数据已经被更新,导致对比相等。

解决方案

1. 添加请求锁机制,确保同一email的请求串行处理

用一个Map来记录正在处理的email,避免并发请求干扰:

// 全局维护请求锁
const contactUpdateLocks = new Map();

async function updateContactDetails(updatedUser) {
    // 检查当前email是否正在处理
    if (contactUpdateLocks.has(updatedUser.email)) {
        console.log(`Skipping update for ${updatedUser.email} - already in progress`);
        return;
    }
    contactUpdateLocks.set(updatedUser.email, true);

    const token = await verifyToken();
    let hubspotData;
    try {
        if (!token) throw new Error('Hubspot api token not found.');
        const getUrl = `https://api.hubapi.com/contacts/v1/contact/email/${updatedUser.email}/profile`;
        const response = await axios.get(getUrl, {
            headers: {
                Authorization: `Bearer ${token}`,
            },
        });
        hubspotData = {
            firstname: response.data.properties?.firstname?.value,
            lastname: response.data.properties?.lastname?.value,
            email: response.data.properties?.email?.value,
        };
        console.log('🚀 ~ updateContactDetails ~ updatedUser:', updatedUser);
        console.log('🚀 ~ updateContactDetails ~ hubspotData:', hubspotData);

        if (!_.isEqual(hubspotData, updatedUser)) {
            console.log("not equal - making post request")
            console.log('🚀 ~ updateContactDetails ~ updating');
            const updateUrl = `https://api.hubapi.com/contacts/v1/contact/createOrUpdate/email/${updatedUser.email}`;
            const response = await axios.post(
                updateUrl,
                {
                    properties: [
                        {
                            property: 'firstname',
                            value: updatedUser.firstname,
                        },
                        {
                            property: 'lastname',
                            value: updatedUser.lastname,
                        },
                        {
                            property: 'email',
                            value: updatedUser.email,
                        },
                    ],
                },
                {
                    headers: {
                        Authorization: `Bearer ${token}`,
                    },
                }
            );
            const action = response.data.isNew ? 'create' : 'update';
            console.log(`Contact ${action}d with ${response.config.data}`);
        } else {
            console.log('Hubspot contact matches user input');
        }
    } catch (e) {
        if (e.message.includes('token not found')) {
            console.log('Hubspot API - token error:', e);
        } else if (e.response?.data) {
            console.log('Hubspot API - error:', e.response.data);
        } else {
            console.log('Hubspot API - unexpected error:', e);
        }
    } finally {
        // 释放锁
        contactUpdateLocks.delete(updatedUser.email);
    }
}

2. 检查函数调用时机

  • 前端场景:确认按钮点击、表单提交等触发函数的事件是否被重复绑定,导致多次调用。
  • 后端场景:检查是否有定时任务、webhook等重复触发该函数。

3. 验证执行顺序(调试用)

在GET和POST请求前后添加时间戳日志,确认实际执行顺序:

// 在GET请求前添加
console.log(`[${new Date().toISOString()}] Starting GET for ${updatedUser.email}`);
// GET请求后添加
console.log(`[${new Date().toISOString()}] Completed GET for ${updatedUser.email}`);
// POST请求前添加
console.log(`[${new Date().toISOString()}] Starting POST for ${updatedUser.email}`);
// POST请求后添加
console.log(`[${new Date().toISOString()}] Completed POST for ${updatedUser.email}`);

总结

这种异步流程异常通常是并发调用导致的资源竞争,通过添加请求锁确保同一资源的操作串行化,就能解决GET和POST的顺序干扰问题。

内容的提问来源于stack exchange,提问作者o-mac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 07:12:17