如何在Node.js循环中控制请求速率以适配外部API限流规则
原有代码问题
你之前的逻辑用同步for循环触发异步回调请求,会在极短时间内把100个请求全部发出去,自然会触发API限流,throttle方法没生效是因为没有和异步执行流程做绑定,无法阻塞后续请求发送。
实现代码
const throttledRequest = async (access_token, ids) => { // 工具函数:等待指定毫秒数 const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) // 工具函数:把回调风格的接口转为Promise,方便async/await控制 const getLaps = (stravaId) => { return new Promise((resolve, reject) => { const strava = new stravaApi.client(access_token) strava.activities.listLaps({ id: stravaId }, (err, payload) => { if (err) return reject(err) resolve(payload) }) }) } // 把id按每100个拆分为一个批次 const batchSize = 100 const batches = [] for (let i = 0; i < ids.length; i += batchSize) { batches.push(ids.slice(i, i + batchSize)) } // 逐批处理 for (let i = 0; i < batches.length; i++) { const currentBatch = batches[i] console.log(`开始处理第${i+1}批,共${currentBatch.length}个请求`) // 批量执行当前批次的请求,如果需要控制批次内并发,可自行调整,比如每次并发3个 const batchResults = await Promise.all( currentBatch.map(id => getLaps(id).catch(err => { console.error(`id${id}请求失败:`, err) return null })) ) // 写入结果 batchResults.forEach(payload => { if (!payload) return fs.appendFile("streamjson.json", JSON.stringify(payload), err => { if (err) throw err console.log("写入完成") }) }) // 不是最后一批的话,等待15分钟再执行下一批 if (i !== batches.length - 1) { console.log(`当前批次处理完成,等待15分钟后执行下一批`) await sleep(15 * 60 * 1000) // 15分钟换算为毫秒 } } } // 路由内调用示例 router.get('/activities/:stravaId', limiter, (req, res) => { const access_token = req.user.access_token const ids = [5312632886, 4952161622, /* 剩下的id */] // 注意:该任务属于长耗时任务,不要等待执行完成再返回响应,否则会导致HTTP请求超时 throttledRequest(access_token, ids).catch(err => console.error('批量任务执行失败:', err)) // 直接返回受理响应 res.send('批量请求任务已开始执行') })
额外说明
如果API除了15分钟100次的限流规则外,还有秒级限流要求,可以把批次内的Promise.all替换为逐次/固定并发数的请求逻辑,避免批次内请求过快触发限流。
内容的提问来源于stack exchange,提问作者Handler000
相关产品推荐
相关产品推荐

