Node.js多请求结果整合问题:Spotify API获取全部收藏曲目失败求助
解决Spotify API分页获取收藏曲目异步问题
首先,你的核心问题是异步请求的执行顺序和结果收集时机不对:
res.send(tracks)在所有异步请求完成前就执行了,所以返回的是还没填充完整的数组- 全局数组
tracks在并发请求下容易出现不可预期的问题 - 错误处理逻辑不完善,
catch直接返回error会导致后续把错误当成total值处理
下面是重构后的完整方案,用async/await让异步逻辑更直观,同时避免全局变量问题:
步骤1:重构getTracks函数
修改函数,让它返回当前分页的曲目列表,同时第一次请求时返回总曲目数。这样可以避免全局变量,让每个请求的结果更可控:
// 单独封装获取单页曲目的函数 async function getSinglePageTracks(offset, accessToken) { const auth = { headers: { Authorization: `Bearer ${accessToken}` } }; try { const response = await axios.get( `https://api.spotify.com/v1/me/tracks?limit=50${offset > 0 ? `&offset=${offset}` : ''}`, auth ); // 转换当前页的曲目格式 const pageTracks = response.data.items.map(element => ({ title: element.track.name, artist: element.track.artists })); return { pageTracks, total: response.data.total }; } catch (error) { console.error('获取曲目失败:', error.response?.data || error.message); throw error; // 抛出错误让上层处理,不要默默吞掉 } }
步骤2:在路由中实现完整的分页逻辑
用async/await等待所有分页请求完成,再合并结果返回给客户端:
router.get('/getsongs', async function (req, res) { try { const access_token = req.query.access; if (!access_token) { return res.status(400).send('缺少access token'); } // 第一次请求获取总曲目数和第一页数据 const firstPageResult = await getSinglePageTracks(0, access_token); let allTracks = [...firstPageResult.pageTracks]; const totalTracks = firstPageResult.total; // 计算需要请求的剩余页数 const totalPages = Math.ceil(totalTracks / 50); if (totalPages > 1) { // 生成所有需要请求的offset数组 const offsets = []; for (let i = 1; i < totalPages; i++) { offsets.push(i * 50); } // 并行请求所有剩余页面 const pagePromises = offsets.map(offset => getSinglePageTracks(offset, access_token)); const remainingPages = await Promise.all(pagePromises); // 合并所有页面的曲目 remainingPages.forEach(page => { allTracks.push(...page.pageTracks); }); } // 所有请求完成后再返回结果 res.send(allTracks); // 后续可以在这里处理随机挑选10首的逻辑 // const randomTracks = allTracks.sort(() => Math.random() - 0.5).slice(0, 10); // res.send(randomTracks); } catch (error) { res.status(500).send('获取曲目列表失败'); } });
关键改进点说明
- 避免全局变量:用局部变量
allTracks收集所有结果,不会有并发请求的冲突问题 - 异步流程可控:用
async/await和Promise.all确保所有分页请求完成后再返回结果,解决了res.send提前执行的问题 - 错误处理完善:在函数内抛出错误,上层统一捕获处理,避免错误被当成正常数据处理
- 并行请求优化:剩余页面用
Promise.all并行请求,比串行请求效率更高(Spotify API的并发限制足够支持这种场景)
如果你想更严谨一点,也可以用递归的方式串行请求,但并行请求在大多数情况下效率更高,只要不超过API的速率限制就没问题。
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

