【问题标题】:API Request PaginationAPI 请求分页
【发布时间】:2017-10-21 12:14:56
【问题描述】:

我正在向 Github 发出一个简单的 API 请求以获取所有存储库。问题是 Github 有一个限制,每个请求最多可以发送 100 个。有些用户拥有超过 100 个仓库,我不知道如何访问它或如何进行分页。

我正在像这样使用 Axios 发出 GET 请求:

https://api.github.com/users/<AccountName>/repos?per_page=100

我也可以这样放页码

https://api.github.com/users/<AccountName>/repos?page=3&per_page=100

但是如何在不发出 10 个 API 请求的情况下在应用程序中进行这项工作?我什至不知道我应该提出多少请求,因为我不知道返回的数字是多少,有人有 100 或 1000 个回购吗?例如,我希望将所有内容返回并保存在数组中。

编辑: 示例:我正在传递 accountName

var config = {
  headers: {'Authorization': `token ${ACCESS_TOKEN}`}
}

const REQUEST: string = 'https://api.github.com/users/'

const apiCall = {
  getData: async function (accountName) {
    const encodedAccountName = encodeURIComponent(accountName)
    const requestUrl = `${REQUEST}${encodedAccountName}`

    const user = await axios.get(requestUrl, config)
// This return user and inside of user there is a link for fetching repos
    const repo = await axios.get(`${user.data.repos_url}?per_page=100`, config)

    ...

【问题讨论】:

  • 你有任何代码并且你尝试过对请求进行睡眠吗?
  • 嗨,迈克·通克。我用代码更新了问题。

标签: api reactjs github axios


【解决方案1】:

您可以通过首先从用户帐户 URL 请求来获取 repo 计数。例如这里是我的:

https://api.github.com/users/erikh2000

那里的响应包含一个“public_repos”值。砰!这就是你想要的神奇数字。

如果 repo 计数超过 100,您接下来需要进行多次提取。我知道您不想这样做,但是嘿...不能责怪网络服务试图节省带宽。好消息是您可以将它们放在 Promise.all() 块中,让它们一起获取并立即返回。所以代码就像...

const fetchAllTheRepos = (userName, repoCount) => {
  const MAX_PER_PAGE = 100;
  const baseUrl = 'https://api.github.com/users/' + userName +
    '/repos?per_page=' + MAX_PER_PAGE;

  //Start fetching every page of repos.
  const fetchPromises = [], pageCount = Math.ceil(repoCount / 
    MAX_PER_PAGE);
  for (let pageI = 1; pageI <= pageCount; ++pageI) {
    const fetchPagePromise = fetch(baseUrl + '&page=' + pageI);
    fetchPromises.push(fetchPagePromise);
  }

  //This promise resolves after all the fetching is done.
  return Promise.all(fetchPromises)
  .then((responses) => {
     //Parse all the responses to JSON.
     return Promise.all( responses.map((response) => response.json()) );
  }).then((results) => {
    //Copy the results into one big array that has all the friggin repos.
    let repos = [];
    results.forEach((result) => {
      repos = repos.concat(result);
    });
    return repos;
  });
};

//I left out the code to get the repo count, but that's pretty easy.
fetchAllTheRepos('erikh2000', 7).then((repos) => {
    console.log(repos.length);
});

同时获取所有页面最终可能超出 Github 想要让您为那些拥有大量存储库的帐户一次性完成的工作。我会对您尝试一次获得的回购数量设置一些“好公民”限制,例如1000. 然后通过观察 HTTP 错误响应来查看 api.github.com 是否同意您对好公民的定义。如果需要,您可以进入节流解决方案,但可能像上面这样的“一次全部获取”方法可以正常工作。

另一方面,如果您在一个会话中浏览多个帐户,那么也许从一开始就设计节流,只是为了让您知道......为此,请查看队列/工作者模式。

【讨论】:

  • 感谢埃里克。我会检查这个。是的,我也首先获取用户,然后从用户获取链接并获取存储库。我用我的代码示例更新了这个问题。我现在将尝试合并您的。让我们把孩子带回家吧。如果您也有建议如何将我的示例与您的示例结合,请在此处写下。我这里有点缺水。
  • 我还发现有一个 npm 包parse-link-header 可以解析返回的标头,并且在标头内部有一个页面总数和一个可以放入 api 调用的下一页链接并获取数据。不知道我将如何使用它,也许是某种循环。
  • 伊戈尔,我想你已经掌握了一切。我不想将我的代码转换为 Axios fetches,但我假设 ES6 fetches 会稍微考虑一下。您对用户 URL 的请求 (const user = await axios.get(requestUrl, config)) 将为您提供 repo 计数 (user.data.public_repos),然后您需要与上面的 fetchAllTheRepos() 函数中提供的相同逻辑.
  • 谢谢埃里克。我做到了。你的逻辑很好用,我只是转而使用 axios 和 async/await。谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-06-10
  • 2018-11-04
  • 2013-07-20
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 2013-08-31
  • 1970-01-01
相关资源
最近更新 更多