Android调用GitHub API搜索仓库无法获取完整JSON响应
解决Android请求GitHub Search API仅返回部分数据的问题
嘿,我之前也踩过这个坑!你遇到的情况其实是因为GitHub Search API本身有分页限制,浏览器里看到的“完整内容”其实只是第一页的结果,默认情况下API只会返回30条仓库数据,剩下的内容需要通过分页参数主动请求才能拿到。下面给你针对不同网络库的具体解决办法:
为什么会只拿到部分数据?
GitHub的Search API有两个关键限制:
- 默认每页返回30条结果,最多允许每页请求100条(通过
per_page参数设置) - 未认证的请求每小时最多10次,认证后(用Personal Access Token)可以提升到30次,频繁请求会触发403错误
你现在拿到的就是第一页的30条数据,不是完整的搜索结果集。
用Retrofit解决的步骤
1. 改造API接口,添加分页参数
在你的Retrofit接口里加上page(页码,从1开始)和per_page参数:
// Kotlin示例,Java写法类似 interface GitHubApiService { @GET("search/repositories") suspend fun searchRepositories( @Query("q") query: String, @Query("sort") sort: String, @Query("order") order: String, @Query("page") page: Int, @Query("per_page") perPage: Int = 100 // 设为最大值减少请求次数 ): Response<RepositorySearchResponse> }
2. 循环请求所有分页数据
你需要写一个循环逻辑,从第1页开始请求,直到没有下一页为止:
suspend fun fetchAllRepos(query: String): List<Repository> { val allRepos = mutableListOf<Repository>() var currentPage = 1 val perPage = 100 var hasNextPage = true while (hasNextPage) { val response = githubApiService.searchRepositories(query, "stars", "desc", currentPage, perPage) if (response.isSuccessful) { val searchResult = response.body() searchResult?.items?.let { allRepos.addAll(it) } // 检查响应头的Link字段,判断是否有下一页 val linkHeader = response.headers()["Link"] hasNextPage = linkHeader?.contains("rel=\"next\"") == true currentPage++ } else { // 处理错误,比如rate limit触发的403 hasNextPage = false } } return allRepos }
3. 建议添加认证
在Retrofit的OkHttpClient里添加Authorization头,提升请求限额:
val okHttpClient = OkHttpClient.Builder() .addInterceptor { chain -> val originalRequest = chain.request() val authenticatedRequest = originalRequest.newBuilder() .header("Authorization", "token YOUR_PERSONAL_ACCESS_TOKEN") .build() chain.proceed(authenticatedRequest) } .build()
用AsyncHttpClient解决的步骤
1. 手动拼接分页参数并处理分页逻辑
在请求URL里加上page和per_page,然后通过响应头的Link字段判断是否有下一页:
private void fetchAllRepos() { AsyncHttpClient client = new AsyncHttpClient(); int currentPage = 1; final int perPage = 100; fetchPage(client, currentPage, perPage); } private void fetchPage(AsyncHttpClient client, int page, int perPage) { String url = String.format( "https://api.github.com/search/repositories?q=json%%20parser&sort=stars&order=desc&page=%d&per_page=%d", page, perPage ); client.get(url, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { // 解析当前页的JSON数据,添加到全局列表 String json = new String(responseBody); parseAndAddRepos(json); // 检查是否有下一页 String linkHeader = getHeaderValue(headers, "Link"); if (linkHeader != null && linkHeader.contains("rel=\"next\"")) { // 解析下一页的URL String nextPageUrl = extractNextPageUrl(linkHeader); fetchPage(client, page + 1, perPage); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { // 处理请求失败,比如网络错误或rate limit Log.e("GitHubAPI", "Request failed: " + error.getMessage()); } }); } // 工具方法:获取指定头的值 private String getHeaderValue(Header[] headers, String name) { for (Header header : headers) { if (name.equals(header.getName())) { return header.getValue(); } } return null; } // 工具方法:从Link头提取下一页URL private String extractNextPageUrl(String linkHeader) { // Link头格式类似:<https://api.github.com/...&page=2>; rel="next", <...>; rel="last" String[] parts = linkHeader.split(","); for (String part : parts) { if (part.contains("rel=\"next\"")) { int start = part.indexOf("<") + 1; int end = part.indexOf(">"); return part.substring(start, end); } } return null; }
额外注意事项
- 不要一次性请求过多页面,避免触发rate limit(可以通过响应头的
X-RateLimit-Remaining查看剩余请求次数) - 记得在后台线程处理网络请求,不要阻塞主线程
- 可以给用户展示加载状态,避免用户以为请求卡住了
内容的提问来源于stack exchange,提问作者Sathish
相关产品推荐
相关产品推荐

