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

如何使用libcurl从GitHub Release下载.zip/rar归档文件?

问题:使用libcurl下载GitHub Release归档文件失败,返回CURL_OK但无数据写入

下载普通HTML页面时一切正常,但下载GitHub Release的.zip格式归档文件却失败。奇怪的是curl_easy_perform返回了CURL_OK状态,但文件中没有写入任何数据块。

我的代码

typedef size_t(*CurlWriteDataFn)(void* ptr, size_t size, size_t nmemb, FILE* stream);

// 自定义写入函数(参考示例实现)
static size_t CurtWriteData(void* ptr, size_t size, size_t nmemb, FILE* stream) {
    size_t written = fwrite(ptr, size, nmemb, stream);
    return written;
}

// 下载函数
static void DownloadFile(const std::string& url, const std::string outFilePath, CurlWriteDataFn writeFn) {

    // 检查URL和输出路径
    if (url.empty()) {
        // Curl: URL未设置
        return;
    }
    if (outFilePath.empty()) {
        // Curl: 输出文件路径未设置
        return;
    }

    CURL* curl;
    FILE* fp;
    CURLcode res;

    curl = curl_easy_init();
    if (!curl) {
        // Curl: 初始化库失败
        return;
    }

    // 复制URL和输出路径(确保char*始终有效)
    std::string _url         = url;
    std::string _outFilePath = outFilePath;

    fp = fopen(_outFilePath.c_str(), "wb");
    if (!fp) {
        // Curl: 打开文件失败
        curl_easy_cleanup(curl);
        return;
    }

    // 设置库选项
    curl_easy_setopt(curl, CURLOPT_URL, _url.c_str());
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");
    
    // 注:也曾尝试过其他UserAgent,比如:
    // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"); 
    // 但仍然无效
    
    if (writeFn)
       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFn);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

    // 执行下载
    res = curl_easy_perform(curl);
    if (res != CURLcode::CURLE_OK) {
        // Curl: 下载文件失败
    }

    curl_easy_cleanup(curl);
    fclose(fp);
}

int main() {
   // 正常下载
   // DownloadFile("https://curl.se/mail/lib-2010-11/0182.html", "C:\\MyDownloads\\some.json", CurtWriteData); 
   
   // 下载失败(无错误码返回)
   DownloadFile("https://github.com/KennyProgrammer/TestRepo/archive/refs/tags/v0.0.1.zip", "C:\\MyDownloads\\SomeRelease-v0.0.1.zip", CurtWriteData);
   
   return 0;
}

注:我也曾尝试使用http而非https的URL,以及启用SSL peer和主机名验证,但仍然无效。

curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // 验证SSL peer
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); // 验证SSL主机名

解决方法

1. 启用重定向跟随

GitHub的Release归档链接通常会返回3xx重定向(跳转到GitHub的CDN地址),但libcurl默认不会自动跟随重定向。添加以下选项开启该功能:

curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// 可选:设置最大重定向次数,避免无限循环
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L);

2. 检查HTTP响应状态码

即使curl_easy_perform返回CURL_OK,也不代表HTTP请求成功(可能返回404、403等错误码)。下载后获取响应状态码排查问题:

long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code >= 400) {
    fprintf(stderr, "HTTP请求失败,状态码:%ld\n", response_code);
}

3. 优化UserAgent(可选)

部分服务器会对过于简单的UserAgent做限制,使用标准浏览器的UserAgent可以避免被拦截:

curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36");

修改后的完整下载函数

static void DownloadFile(const std::string& url, const std::string outFilePath, CurlWriteDataFn writeFn) {

    if (url.empty() || outFilePath.empty()) {
        return;
    }

    CURL* curl = curl_easy_init();
    if (!curl) {
        return;
    }

    std::string _url = url;
    std::string _outFilePath = outFilePath;

    FILE* fp = fopen(_outFilePath.c_str(), "wb");
    if (!fp) {
        curl_easy_cleanup(curl);
        return;
    }

    curl_easy_setopt(curl, CURLOPT_URL, _url.c_str());
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36");
    // 启用重定向跟随
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L);

    if (writeFn)
       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFn);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fprintf(stderr, "curl下载失败:%s\n", curl_easy_strerror(res));
    } else {
        // 获取HTTP响应状态码
        long response_code;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
        printf("HTTP响应状态码:%ld\n", response_code);
        if (response_code >= 400) {
            fprintf(stderr, "HTTP请求失败,状态码:%ld\n", response_code);
        }
    }

    curl_easy_cleanup(curl);
    fclose(fp);
}

内容的提问来源于stack exchange,提问作者Kenny Tutorials

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:25:26