Swift 从 NSHTTPURLResponse 标头获取下一页

Pab*_*mez 2 api rest swift alamofire

我正在使用一个 API,它可以在名为“链接”的字段内的页眉中提供下一页。(例如 Github 也是这样做的,所以这并不奇怪。Github Doc

我正在使用的服务通过以下方式检索分页数据: 分页信息 正如我们在“链接”中看到的那样,给了我下一页,其中$0.response?.allHeaderFields["Link"]:我明白了</api/games?page=1&size=20>; rel="next",</api/games?page=25&size=20>; rel="last",</api/games?page=0&size=20>; rel="first"

我找到了以下代码来读取页面,但它非常脏......我想知道是否有人处理过同样的问题,或者是否有一个标准的方式来面对它。(我还搜索了 alamofire 是否支持任何类型的功能,但我还没有找到)

  // MARK: - Pagination
  private func getNextPageFromHeaders(response: NSHTTPURLResponse?) -> String? {
    if let linkHeader = response?.allHeaderFields["Link"] as? String {
      /* looks like:
      <https://api.github.com/user/20267/gists?page=2>; rel="next", <https://api.github.com/user/20267/gists?page=6>; rel="last"
      */
      // so split on "," the  on  ";"
      let components = linkHeader.characters.split {$0 == ","}.map { String($0) }
      // now we have 2 lines like '<https://api.github.com/user/20267/gists?page=2>; rel="next"'
      // So let's get the URL out of there:
      for item in components {
        // see if it's "next"
        let rangeOfNext = item.rangeOfString("rel=\"next\"", options: [])
        if rangeOfNext != nil {
          let rangeOfPaddedURL = item.rangeOfString("<(.*)>;", options: .RegularExpressionSearch)
          if let range = rangeOfPaddedURL {
            let nextURL = item.substringWithRange(range)
            // strip off the < and >;
            let startIndex = nextURL.startIndex.advancedBy(1) //advance as much as you like
            let endIndex = nextURL.endIndex.advancedBy(-2)
            let urlRange = startIndex..<endIndex
            return nextURL.substringWithRange(urlRange)
          }
        }
      }
    }
    return nil
  }
Run Code Online (Sandbox Code Playgroud)

Lar*_*rme 5

我认为forEach()可以有更好的解决方案,但这是我得到的:

let linkHeader = "</api/games?page=1&size=20>; rel=\"next\",</api/games?page=25&size=20>; rel=\"last\",</api/games?page=0&size=20>; rel=\"first\""

let links = linkHeader.components(separatedBy: ",")

var dictionary: [String: String] = [:]
links.forEach({
    let components = $0.components(separatedBy:"; ")
    let cleanPath = components[0].trimmingCharacters(in: CharacterSet(charactersIn: "<>"))
    dictionary[components[1]] = cleanPath
})

if let nextPagePath = dictionary["rel=\"next\""] {
    print("nextPagePath: \(nextPagePath)")
}

//Bonus
if let lastPagePath = dictionary["rel=\"last\""] {
    print("lastPagePath: \(lastPagePath)")
}
if let firstPagePath = dictionary["rel=\"first\""] {
    print("firstPagePath: \(firstPagePath)")
}
Run Code Online (Sandbox Code Playgroud)

控制台输出:

$> nextPagePath: /api/games?page=1&size=20
$> lastPagePath: /api/games?page=25&size=20
$> firstPagePath: /api/games?page=0&size=20
Run Code Online (Sandbox Code Playgroud)

我使用了components(separatedBy:)not 来split()避免String()最后的转换。我创建了一个Dictionary来保存值并删除了<and>并进行了修剪。