如何使用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
相关产品推荐
相关产品推荐

