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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:21:15