@aim-packages/downloader
v0.2.0
Published
基于 node-downloader-helper 的下载器,支持断点续传、自动重试、代理等特性
Maintainers
Readme
@aim-packages/downloader
由于在 electron 中没有找到好的下载库,以前使用过的 electron-dl 存在一些问题,代理设置也不方便,现在基于 node-downloader-helper 的增强型 Node.js 文件下载库。
✨ 额外功能
本库在 node-downloader-helper 基础上提供了两个额外功能:
- 临时文件机制 - 下载过程中使用
.download后缀的临时文件,下载完成并校验通过后才重命名为最终文件 - SHA256 文件校验 - 下载完成后自动验证文件 SHA256 哈希值,确保文件完整性
- 可选续传校验 - 可在断点续传前通过 HEAD 校验远端资源是否仍是同一文件
📦 安装
pnpm add @aim-packages/downloader🚀 快速开始
import { createDownloader } from '@aim-packages/downloader';
const downloader = createDownloader();
// 基本下载
const filePath = await downloader.download(
'https://example.com/file.zip',
'/path/to/destination/file.zip'
);
// 带 SHA256 校验的下载
await downloader.download(
'https://example.com/file.zip',
'/path/to/destination/file.zip',
{
sha256: 'expected-sha256-hash-value'
}
);
// 开启续传前 HEAD 校验(默认关闭,以保持旧版本行为兼容)
await downloader.download(
'https://example.com/file.zip',
'/path/to/destination/file.zip',
{
resumeValidation: true,
debug: true
}
);💡 使用示例
使用 AbortSignal 取消下载
import { createDownloader, DownloadCancelledError } from '@aim-packages/downloader';
const downloader = createDownloader();
const abortController = new AbortController();
// 5 秒后取消下载
setTimeout(() => {
abortController.abort();
}, 5000);
try {
await downloader.download(
'https://example.com/file.zip',
'/path/to/destination/file.zip',
{
signal: abortController.signal
}
);
} catch (error) {
if (error instanceof DownloadCancelledError) {
console.log('下载已取消');
}
}使用代理下载
import { createDownloader } from '@aim-packages/downloader';
import { HttpsProxyAgent } from 'https-proxy-agent';
const downloader = createDownloader();
const proxyAgent = new HttpsProxyAgent('http://proxy.example.com:8080');
await downloader.download(
'https://example.com/file.zip',
'/path/to/destination/file.zip',
{
proxyAgent
}
);🔧 技术细节
调试日志
- 默认不打印内部下载日志,避免库在宿主项目里产生额外输出
- 传入
debug: true后会打印下载开始、续传校验、重试、失败等内部日志 - 下载失败仍会通过 Promise reject 抛出,不依赖日志传递错误信息
临时文件机制
- 下载过程中使用
.download后缀的临时文件(例如:file.zip.download) - 下载完成后进行 SHA256 校验(如果提供)
- 校验通过后才重命名为最终文件(去掉
.download后缀) - 校验失败自动删除文件并抛出
HashMismatchError
SHA256 校验
- 如果提供了
sha256选项,下载完成后会自动计算文件的 SHA256 哈希值 - 如果哈希值不匹配,会抛出
HashMismatchError并删除文件 - 如果哈希值匹配,文件会重命名为最终文件名
续传前 HEAD 校验
默认情况下,本库保持旧版本行为:直接使用 node-downloader-helper 的 resumeIfFileExists 能力,不额外发送 HEAD 校验请求。
如果传入 resumeValidation: true,下载器会:
- 为临时文件维护元信息文件,默认路径为
${destinationPath}.download.meta.json - 首次开始下载前通过 HEAD 记录
ETag、Last-Modified、Content-Length、Accept-Ranges - 下次发现
.download临时文件时,再次 HEAD 并比较远端资源标识 - 只有强 ETag 或 Last-Modified 匹配,且默认要求
Accept-Ranges: bytes时才继续续传 - 如果资源标识缺失或不匹配,会删除旧
.download和旧元信息,从头下载 - 下载成功、重命名成功后会清理元信息
- hash 校验失败、文件大小校验失败或重命名失败时,会删除临时文件和元信息
也可以传入更细的配置:
await downloader.download(url, filePath, {
resumeValidation: {
enabled: true,
metadataPath: `${filePath}.resume.json`,
requireRangeSupport: true,
allowSizeOnlyResume: false,
headTimeoutMs: 30000
}
});📋 错误类型
HashMismatchError
Hash 校验失败错误。
class HashMismatchError extends Error {
constructor(
message?: string,
public readonly expected?: string,
public readonly actual?: string
);
}DownloadCancelledError
下载取消错误。当通过 AbortSignal 取消下载时抛出。
class DownloadCancelledError extends Error {
constructor(message?: string);
}