使用libcurl下载:如何预检查字节范围支持及获取Accept-Ranges头?
libcurl断点续传:预先检查服务器范围请求支持的方案
你遇到的核心问题是:用CURLOPT_RANGE做断点续传时,若服务器不支持范围请求会返回完整文件,导致本地文件追加后体积过大。下面提供两种可靠的检查方案,以及获取Accept-Ranges字段的具体实现:
一、通过HEAD请求解析响应头判断支持性
libcurl没有直接提供获取Accept-Ranges的内置宏,必须通过自定义头回调函数解析响应头。步骤如下:
- 发送HEAD请求(仅获取响应头,不下载内容)
- 在回调函数中匹配
Accept-Ranges字段,判断其值是否为bytes
代码示例
#include <curl/curl.h> #include <string.h> #include <stdio.h> // 自定义头回调:提取Accept-Ranges字段 size_t parse_header(char *buffer, size_t size, size_t nitems, void *userdata) { size_t len = size * nitems; char *range_header = strstr(buffer, "Accept-Ranges: "); if (range_header) { // 截取字段值,去除换行符 char *value = range_header + strlen("Accept-Ranges: "); value[strcspn(value, "\r\n")] = '\0'; // 标记是否支持字节范围请求 *(int*)userdata = (strcmp(value, "bytes") == 0) ? 1 : 0; } return len; } int main() { CURL *curl = curl_easy_init(); if (!curl) return 1; int supports_range = 0; const char *url = "你的下载URL"; // 配置HEAD请求 curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); // 只取响应头 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parse_header); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &supports_range); // 执行请求 CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { if (supports_range) { printf("服务器支持字节范围请求\n"); // 此处执行断点续传逻辑:获取本地文件大小,设置CURLOPT_RANGE } else { printf("服务器不支持范围请求,需重新下载完整文件\n"); } } curl_easy_cleanup(curl); return 0; }
二、通过小范围请求验证(更可靠)
部分服务器可能对HEAD请求的响应与GET不一致,此时直接发送一个极小范围的请求(比如请求第0个字节),通过响应码判断:
- 响应码为
206 Partial Content:支持范围请求 - 响应码为
200 OK:不支持范围请求,会返回完整文件
代码示例
CURL *curl = curl_easy_init(); if (!curl) return 1; const char *url = "你的下载URL"; long resp_code = 0; // 请求0-0范围的字节 curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_RANGE, "0-0"); curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); // 可选:只取响应头,避免下载1字节 CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp_code); if (resp_code == 206) { printf("服务器支持范围请求\n"); // 执行断点续传 } else if (resp_code == 200) { printf("服务器不支持范围请求\n"); // 删除本地不完整文件,重新下载 } } curl_easy_cleanup(curl);
断点续传的安全逻辑
确认服务器支持范围请求后,再执行续传:
- 获取本地已下载文件的大小(用
stat或fseek+ftell) - 设置
CURLOPT_RANGE为[已下载字节数]-(例如本地已下1024字节,设为1024-) - 打开本地文件时使用追加模式(
fopen(file, "ab"))或定位到文件末尾写入(fseek(fp, 0, SEEK_END))
如果服务器不支持范围请求,务必删除本地不完整文件后重新下载,避免追加完整文件导致体积翻倍。
内容的提问来源于stack exchange,提问作者TWitvliet
相关产品推荐
相关产品推荐

