You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:24:39