一、基础概念(必考)
1. 客户端与服务端
-
客户端:请求数据的一端(本机程序)
-
服务端:提供资源、响应请求的一端(云端服务器)
2. HTTP 协议与工具类
-
HttpClient :.NET 官方 HTTP 请求客户端,专门用于 网络上传、下载、接口请求
-
URL:资源网络地址(完整访问地址)
-
URI:URL 转换后的统一资源唯一标识,程序请求必须使用 URI 对象
3. 三种 HTTP 请求方式(本案例核心)
-
HEAD :只请求响应头,只获取文件信息(大小、类型),不下载内容、速度极快
-
GET :请求服务器资源正文,用于真正下载文件数据
-
POST:向服务器提交数据(本案例未使用)
二、核心功能介绍
本项目实现完整工业级下载功能:
-
自定义保存路径(文件夹选择器)
-
分片下载:大文件分块分批下载,避免一次性加载内存溢出
-
断点续传:暂停/关闭程序后,再次下载自动从已下载位置接续,不重复下载
-
任务取消:基于 CancellationTokenSource 安全终止下载
-
实时进度更新:进度条 + 百分比文本实时刷新
-
按钮状态锁定(防止重复点击冲突)
三、核心技术原理详解
1. 断点续传原理
-
下载前判断本地文件是否存在
-
存在:读取 本地文件现有长度,作为下次下载的起始位置
-
通过 Range 请求头 告诉服务器:从指定字节位置继续返回数据
-
文件流使用 Append 追加模式,保留已有数据,续写新数据
2. 分片下载原理
-
将超大文件切分为 1000 字节小分片
-
循环请求每一段分片数据、逐段写入本地
-
解决一次性读取超大文件导致的 内存溢出、卡顿 问题
3. RangeHeaderValue 核心
RangeHeaderValue(start,end):限定本次请求的文件字节范围,是分片/断点下载的核心请求头
4. 取消机制
使用 CancellationTokenSource 令牌,安全终止 HttpClient 请求与循环,杜绝强行终止导致的文件损坏、线程卡死。
四、完整代码分层解析
1. 全局对象定义
cs
// 全局唯一HTTP请求客户端(推荐全局静态,避免频繁创建销毁)
public static readonly HttpClient httpClient = new HttpClient();
// 取消令牌:控制下载终止
public CancellationTokenSource cts;
2. 选择保存路径
通过 FolderBrowserDialog 选择文件夹,赋值给文本框,作为文件保存根目录。
3. 下载按钮核心逻辑
-
非空校验:必须设置保存路径、资源URL
-
锁定界面按钮,防止重复点击
-
新建取消令牌
-
Task.Run 开启后台下载(不卡死UI)
-
ContinueWith 回调:下载完成解锁界面、提示完成
4. 核心 Download 下载方法(重点)
第一步:HEAD 请求获取文件总大小
使用 HEAD 方式请求,只读取响应头 ContentLength,获取服务器文件真实大小,不下载内容,高效快速。
第二步:判断本地文件,实现断点续传
-
文件不存在:startPosition=0,从头创建下载
-
文件存在:读取已有长度,从当前位置续写
-
已下载完整:直接抛出异常"文件已下载完成"
第三步:分片循环下载
-
固定分片大小 1000 字节
-
设置 Range 分段请求头
-
GetAsync 获取分段数据
-
文件流追加写入
-
更新下载位置、刷新UI进度
5. 取消下载逻辑
cts.Cancel() 触发取消信号,循环检测 IsCancellationRequested 终止下载,重置所有界面状态。
6. 简单 Get 接口请求演示
通过 GetAsync 直接请求网页接口,读取字符串返回结果,适用于普通接口调用。
五、必考知识点总结
-
HEAD 与 GET 区别:HEAD拿文件信息,GET拿文件内容
-
断点续传核心:判断本地文件长度 + Range请求头 + 文件追加模式
-
分片下载核心:切割字节范围,循环分段请求,防止内存溢出
-
异步不卡UI:Task.Run 后台执行耗时下载,Invoke 更新界面
-
安全取消任务:CancellationToken 优雅终止,杜绝暴力终止报错
-
URI 作用:将URL字符串转为程序可识别的统一资源对象
-
HttpClient 规范:全局静态单例使用,不重复 new,避免端口耗尽
六、代码易错点
-
下载属于耗时操作,必须放子线程,直接主线程下载会卡死UI
-
更新进度条、文本必须 Invoke,子线程不能直接操作UI
-
每次下载必须 new 新的 CancellationTokenSource,令牌不可复用
-
文件结尾分片需要判断边界,防止 end 超出总文件大小
-
断点续传必须使用 FileMode.Append 追加模式