【问题标题】:How to parse link header from github API如何从 github API 解析链接头
【发布时间】:2012-02-02 21:09:07
【问题描述】:

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

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(我想),我想问一下是否有人有一个有用的小 sn-p 来解析链接头(例如将其转换为数组),以便我可以将它用于我的 js 应用程序。

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

【问题讨论】:

    标签: javascript json github jsonp github-api


    【解决方案1】:

    这是一个用于此目的的 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;
            }
    

    【讨论】:

      【解决方案2】:

      对于最终在 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);
      

      【讨论】:

      • 我可以确认,这适用于那些寻找 Java 解决方案而又不想使用任何第三方库的人。
      【解决方案3】:

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

      var parse = require('parse-link-header');
          var parsed = parse(res.headers.link);
          no_of_pages = parsed.last.page;
      

      【讨论】:

        【解决方案4】:

        这是一个 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]
        

        【讨论】:

          【解决方案5】:

          这是一个简单的 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"
            }
          }
          

          【讨论】:

            【解决方案6】:

            这是一个使用 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
            

            【讨论】:

              【解决方案7】:

              我完全理解这是“技术上”的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);
              }
              

              【讨论】:

                【解决方案8】:

                如果你可以使用 Python 并且不想实现 full specification,但需要一些适用于 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)
                

                【讨论】:

                • 如果你正在使用请求,你可以通过rsp.links获取它。
                • 感谢@kxxoling 的links 提示,我不知道!
                【解决方案9】:

                The parse-link-header NPM module 就是为此目的而存在的; its source can be found on github 在 MIT 许可下(免费用于商业用途)。

                安装很简单:

                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.nextparsed.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' } }
                

                【讨论】:

                • 包括原始来源的基本部分,因为如果链接失效,答案将变得无用!
                • 是的,听起来规则需要修改。暂时你可以让社区知道,在此之后我的贡献动力已经减弱。感谢您的编辑。但是,如果链接被删除(节点模块被删除),您在我的消息中编辑的信息将同样无用。我发现很难理解制定规则以否决/删除试图帮助的人的帖子的常识,实际上没有做错任何事情(这是一个节点模块,也许有些人不明白那是什么... )
                • 另外请记住,堆栈溢出不会给我带来报酬。我是由我的雇主支付的,为此我花了尽可能少的时间后重新开始工作,以帮助他人,在其堆栈溢出问题被证明提供了不正确的信息之后。如果您认为我提供的准确信息不值得,请随时删除我的帖子。如果您认为下次我应该花更多时间在我的帖子上,也可以随时向我提供报价,我会安排时间并在下班后发表专业帖子。 Stackoverflow 是社区驱动的,但它是一项业务。
                • 同时接受的答案仅提供链接,3 年来没有人对此发表任何评论。这简直太荒谬了......
                • 这是 javascript 的最佳答案。
                【解决方案10】:

                我发现了这个Gist

                在 JavaScript 中解析 Github Links 标头

                在 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"
                };
                

                【讨论】:

                  【解决方案11】:

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

                  【讨论】:

                    【解决方案12】:

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

                    【讨论】:

                    • 值得注意的是,虽然这对 GitHub 的使用起到了作用,但这并不是对任何 Link 标头的完全健壮的解析。字符串拆分是不够的;例如;= 允许在 URL 中使用,如果值被引用,甚至 , 也允许在值中使用。极其复杂。规格:rfc-editor.org/rfc/rfc5988.txt
                    猜你喜欢
                    • 1970-01-01
                    • 2021-06-20
                    • 2019-12-30
                    • 2021-10-12
                    • 2020-09-08
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-02-05
                    相关资源
                    最近更新 更多