37

github API 在 http 链接头中发送 json 结果的分页数据:

Link: <https://api.github.com/repos?page=3&per_page=100>; rel="next",
<https://api.github.com/repos?page=50&per_page=100>; rel="last"

因为 github API 不是唯一使用这种方法的 API(我想),所以我想问一下是否有人有一个有用的小片段来解析链接头(例如将其转换为数组),以便我可以将它用于我的js 应用程序。

我四处搜索,但没有发现关于如何从 json API 解析分页的有用信息

4

12 回答 12

21

parse-link-header NPM 模块就是为此目的而存在的;它的源代码可以在 MIT 许可下在 github 上找到(免费用于商业用途)。

安装很简单:

npm install parse-link-header

用法如下所示:

var parse = require('parse-link-header');
var parsed = parse('<https://api.github.com/repos?page=3&per_page=100>; rel="next", <https://api.github.com/repos?page=50&per_page=100>; rel="last"')

...之后有parsed.next,parsed.last等:

{ next:
   { page: '3',
     per_page: '100',
     rel: 'next',
     url: 'https://api.github.com/repos?page=3&per_page=100' },
  last:
   { page: '50',
     per_page: '100',
     rel: 'last',
     url: ' https://api.github.com/repos?page=50&per_page=100' } }
于 2015-04-30T17:36:08.927 回答
17

GitHub Java API中有一个PageLinks类,它显示了如何解析标头。Link

于 2012-01-07T04:12:44.027 回答
8

我发现这个要点

Links在 JavaScript 中解析 Github标头

在 Github API 上对其进行了测试,它返回了一个对象,例如:

var results = {
    last: "https://api.github.com/repositories/123456/issues?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=open&since=2013-07-24T02%3A12%3A30.309Z&direction=asc&page=4"
    next: "https://api.github.com/repositories/123456/issues?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=open&since=2013-07-24T02%3A12%3A30.309Z&direction=asc&page=2"
};
于 2013-08-23T13:30:41.747 回答
6

我在 github 上找到了 wombleton/link-headers 。它似乎是为浏览器制作的,而不是一个 npm 模块,但看起来修改它以在服务器端环境中工作并不难。它使用 pegjs 生成真正的 RFC 5988 解析器而不是字符串拆分,因此它应该适用于任何链接头,而不仅仅是 Github 的。

于 2013-05-26T14:05:51.783 回答
4

我完全理解这是“技术上”的一个JavaScript线程。但是,如果您像我一样通过 Google 的“如何解析链接标头”来到这里,我想我会为我的环境(C#)分享我的解决方案。

public class LinkHeader
{
    public string FirstLink { get; set; }
    public string PrevLink { get; set; }
    public string NextLink { get; set; }
    public string LastLink { get; set;}

    public static LinkHeader FromHeader(string linkHeader)
    {
        LinkHeader linkHeader = null;

        if (!string.IsNullOrWhiteSpace(linkHeader))
        {
            string[] linkStrings = linkHeader.Split("\",");

            if (linkStrings != null && linkStrings.Any())
            {
                linkHeader = new LinkHeader();

                foreach (string linkString in linkStrings)
                {
                    var relMatch = Regex.Match(linkString, "(?<=rel=\").+?(?=\")", RegexOptions.IgnoreCase);
                    var linkMatch = Regex.Match(linkString, "(?<=<).+?(?=>)", RegexOptions.IgnoreCase);

                    if (relMatch.Success && linkMatch.Success)
                    {
                        string rel = relMatch.Value.ToUpper();
                        string link = linkMatch.Value;

                        switch (rel)
                        {
                            case "FIRST":
                                linkHeader.FirstLink = link;
                                break;
                            case "PREV":
                                linkHeader.PrevLink = link;
                                break;
                            case "NEXT":
                                linkHeader.NextLink = link;
                                break;
                            case "LAST":
                                linkHeader.LastLink = link;
                                break;
                        }
                    }
                }
            }
        }

        return linkHeader;
    }
}

使用 GitHub 的示例链接头在控制台应用程序中进行测试:

void Main()
{
    string link = "<https://api.github.com/user/repos?page=3&per_page=100>; rel=\"next\",< https://api.github.com/user/repos?page=50&per_page=100>; rel=\"last\"";
    LinkHeader linkHeader = LinkHeader.FromHeader(link);
}
于 2017-09-20T17:18:18.547 回答
3

这是一个简单的 javascript 函数,它以漂亮的对象表示法从链接中提取有用的信息。

var linkParser = (linkHeader) => {
  let re = /<([^\?]+\?[a-z]+=([\d]+))>;[\s]*rel="([a-z]+)"/g;
  let arrRes = [];
  let obj = {};
  while ((arrRes = re.exec(linkHeader)) !== null) {
    obj[arrRes[3]] = {
      url: arrRes[1],
      page: arrRes[2]
    };
  }
  return obj;
}

它会像这样输出结果==>

{
  "next": {
    "url": "https://api.github.com/user/9919/repos?page=2",
    "page": "2"
  },
  "last": {
    "url": "https://api.github.com/user/9919/repos?page=10",
    "page": "10"
  }
}
于 2019-02-01T06:41:25.877 回答
2

如果您可以使用 Python 并且不想实现完整的规范,但需要有一些适用于 Github API 的东西,那么我们开始:

import re
header_link = '<https://api.github.com/repos?page=3&per_page=100>; rel="next", <https://api.github.com/repos?page=50&per_page=100>; rel="last"'
if re.search(r'; rel="next"', header_link):
    print re.sub(r'.*<(.*)>; rel="next".*', r'\1', header_link)
于 2015-09-30T07:23:29.290 回答
2

这是一个带有 curl 和 sed 的简单 bash 脚本,用于从长查询中获取所有页面

url="https://api.github.com/repos/$GIT_USER/$GIT_REPO/issues"
while [ "$url" ]; do
      echo "$url" >&2
      curl -Ss -n "$url"
      url="$(curl -Ss -I -n "$url" | sed -n -E 's/Link:.*<(.*?)>; rel="next".*/\1/p')"
done > issues.json
于 2019-01-08T10:47:07.113 回答
1

对于最终在 Java 中搜索 Link Header Parser 的人,您可以使用javax.ws.rs.core.Link. 参考下面的例子:

import javax.ws.rs.core.Link

String linkHeaderValue = "<https://api.github.com/repos?page=3&per_page=100>; rel='next'";
Link link = Link.valueOf(linkHeaderValue);
于 2020-10-14T12:29:15.643 回答
0

这是一个 Python 解决方案,用于获取任何 github 存储库的贡献者数量。

import requests
from urllib.parse import parse_qs

rsp = requests.head('https://api.github.com/repos/fabric8-analytics/fabric8-analytics-server/contributors?per_page=1')
contributors_count = parse_qs(rsp.links['last']['url'])['page'][0]
于 2020-07-30T13:12:39.820 回答
0

这是一个简单的代码,用于在 Java Script 中解析来自 GitHub 的链接头

var parse = require('parse-link-header');
    var parsed = parse(res.headers.link);
    no_of_pages = parsed.last.page;
于 2020-08-10T21:13:04.670 回答
0

这是一个用于此目的的 Java 函数,您可以找到提供的参数键和参数值的链接。请注意:这是我出于个人目的制作的东西,对于您的场景可能不是万无一失的,因此请查看并进行相应更改

https://github.com/akshaysom/LinkExtract/blob/main/LinkExtract.java

  public static String getLinkFromLinkHeaderByParamAndValue(String header, String param, String value) {
            if (header != null && param != null && value != null && !"".equals(header.trim()) && !"".equals(param.trim())
                    && !"".equals(value)) {
    
                String[] links = header.split(",");
    
                LINKS_LOOP: for (String link : links) {
    
                    String[] segments = link.split(";");
    
                    if (segments != null) {
    
                        String segmentLink = "";
    
                        SEGMENT_LOOP: for (String segment : segments) {
                            segment = segment.trim();
                            if (segment.startsWith("<") && segment.endsWith(">")) {
    
                                segmentLink = segment.substring(1, segment.length() - 1);
                                continue SEGMENT_LOOP;
    
                            } else {
                                if (segment.split("=").length > 1) {
    
                                    String currentSegmentParam = segment.split("=")[0].trim();
                                    String currentSegmentValue = segment.split("=")[1].trim();
    
                                    if (param.equals(currentSegmentParam) && value.equals(currentSegmentValue)) {
                                        return segmentLink;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }
于 2021-02-09T04:30:13.340 回答