使用libcurl从GitHub仓库下载Zip文件遇0字节问题排查
问题描述
我把一个用WinRAR压缩、内含txt文件的zip包上传到了GitHub测试仓库,尝试用下面的libcurl代码下载指定URL的zip文件:
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) { size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); return written; } void Download(std::string url) { CURL *curl_handle; static const char *pagefilename = "data.zip"; FILE *pagefile; curl_global_init(CURL_GLOBAL_ALL); /* init the curl session */ curl_handle = curl_easy_init(); /* set URL to get here */ curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); /* Switch on full protocol/debug output while testing */ curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); /* disable progress meter, set to 0L to enable and disable debug output */ curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); /* open the file */ pagefile = fopen(pagefilename, "wb"); if(pagefile) { /* write the page body to this file handle */ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); /* get it! */ CURLCode res; res = curl_easy_perform(curl_handle); /* close the header file */ fclose(pagefile); } /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); curl_global_cleanup(); return; } Download("https://github.com/R3uan3/test/files/9544940/test.zip");
CURLCode返回CURLE_OK,但生成的data.zip文件大小为0字节,请问问题出在哪里?
问题排查与解决
未处理GitHub的重定向:GitHub的文件分享链接会自动跳转到实际的文件存储地址,而libcurl默认不开启自动跟随重定向的功能。这时候请求只拿到了重定向响应,没有真正获取到文件内容,导致生成空文件。
解决:在初始化curl会话后添加以下代码,开启自动跟随重定向:curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);文件打开失败未做错误处理:如果
fopen调用失败(比如当前目录没有写入权限、路径不存在),代码会直接跳过下载逻辑,但不会给出任何提示,此时可能生成空文件或者根本不生成文件。
解决:在fopen后增加错误判断逻辑,示例如下:pagefile = fopen(pagefilename, "wb"); if(!pagefile) { printf("无法打开文件进行写入\n"); // 提前清理curl资源 curl_easy_cleanup(curl_handle); curl_global_cleanup(); return; }未检查HTTP响应状态码:
curl_easy_perform返回CURLE_OK仅表示curl库本身没有发生错误,但HTTP请求可能返回4xx/5xx的错误状态码(比如文件不存在、权限不足),这种情况下响应体为空,写入的文件自然是0字节。
解决:在curl_easy_perform执行完成后,添加代码检查HTTP状态码:long response_code; curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code); if(response_code < 200 || response_code >= 300) { printf("HTTP请求失败,状态码:%ld\n", response_code); }
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

