Skip to content

文件下载原理与实现

1. 浏览器如何触发下载

文件下载的核心在于 服务器端 的处理,与前端开发关系不大。浏览器本身具备显示某些资源(如图片、PDF)的能力,但当服务器在响应中加入一个特殊的响应头时,浏览器就会执行下载操作,而不是直接展示文件内容。

关键响应头:Content-Disposition

服务器通过在 HTTP 响应头中添加 Content-Disposition 字段,来告知浏览器这是一个需要下载的附件(attachment),而不是内联显示的内容。

  • 作用:强制触发浏览器的下载行为。
  • 语法
    Content-Disposition: attachment; filename="your-default-filename.ext"
    • attachment: 表明这是一个附件,需要下载。
    • filename: 指定了用户下载时,下载对话框中默认显示的文件名。

HTTP 请求与响应示例

当我们访问一个下载链接时,浏览器会发送一个标准的 GET 请求。关键在于服务器的响应。

http
# 1. 浏览器发送请求
GET /images/wallpaper-1.jpg HTTP/1.1
Host: localhost:8000
...

# 2. 服务器返回响应 (关键部分)
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Disposition: attachment; filename="wallpaper-1.jpg" # <--- 关键响应头
Content-Length: 158276
...

[文件二进制数据]

2. 前端实现普通下载

在前端页面上实现一个标准的下载功能非常简单,只需要一个 <a> 标签即可,无需编写任何 JavaScript 代码。

用户点击链接时,浏览器会向 href 指定的地址发送请求。由于服务器会返回包含 Content-Disposition 头的响应,下载将自动触发。

html
<a href="http://localhost:8000/images/wallpaper-1.jpg">下载壁纸</a>

3. 调用第三方工具下载 (以迅雷为例)

网页之所以能调用迅雷等本地下载工具,是因为这些工具在安装时,会向浏览器中注入相应的 插件 (Extension)。这些插件会监听页面上的特定链接格式,并拦截点击事件,从而唤起本地的下载工具。

迅雷 (Thunder) 的特殊链接格式

要通过迅雷下载,链接的 href 必须遵循其特定的协议和格式。普通 http 链接通常不会被(或在温和模式下不被)拦截。

  • 迅雷专属协议thunder://
  • 链接构造规则
    1. 获取原始的下载地址,例如 http://example.com/file.zip
    2. 在原始地址前后分别添加 AAZZ 作为定界符,构成一个新的字符串:AAhttp://example.com/file.zipZZ
    3. 将这个新字符串进行 Base64 编码
    4. 将编码后的结果与迅雷协议 thunder:// 拼接,形成最终的下载链接。

Base64 编码简介

  • 定义:一种将任意数据(二进制、文本)转换为由 64 个可打印字符组成的文本字符串的编码方法。
  • 64 个可打印字符
    • 大写字母 A-Z (26个)
    • 小写字母 a-z (26个)
    • 数字 0-9 (10个)
    • +/ (2个)
  • JavaScript 实现:浏览器原生提供了 btoa() 函数用于进行 Base64 编码。
    • btoa(): "binary to ASCII",将字符串编码为 Base64。
    • atob(): "ASCII to binary",将 Base64 字符串解码。

通过 JavaScript 动态生成迅雷链接

直接在 HTML 中手写迅雷链接非常繁琐,因为需要手动进行 Base64 编码。通常的做法是使用 JavaScript 动态地将普通下载链接转换为迅雷专用链接。

这可以通过为需要转换的 <a> 标签添加一个自定义属性(如 data-thunder)作为标识来实现。

HTML 结构

html
<a href="http://localhost:8000/images/wallpaper-1.jpg" data-thunder>下载桌面壁纸一 (迅雷)</a>
<a href="http://localhost:8000/images/wallpaper-2.jpg" data-thunder>下载桌面壁纸二 (迅雷)</a>

<a href="http://localhost:8000/images/wallpaper-3.jpg">下载桌面壁纸三 (普通)</a>

JavaScript 实现

javascript
// 1. 选中所有带 data-thunder 属性的 a 标签
// 属性选择器的语法是 [attribute-name] 或 [attribute-name="value"]
const thunderLinks = document.querySelectorAll('a[data-thunder]');

// 2. 遍历这些链接
thunderLinks.forEach(link => {
  // 3. 获取原始的 http 下载地址
  const originalUrl = link.href;

  // 4. 构建迅雷要求的待编码字符串:"AA" + 原始地址 + "ZZ"
  const stringWithBoundary = `AA${originalUrl}ZZ`;

  // 5. 使用 btoa() 函数进行 Base64 编码
  const base64Encoded = btoa(stringWithBoundary);

  // 6. 拼接成最终的迅雷链接
  const thunderUrl = `thunder://${base64Encoded}`;

  // 7. 更新 a 标签的 href 属性
  link.href = thunderUrl;

  console.log(`Original: ${originalUrl} \nConverted: ${thunderUrl}`);
});

经过上述脚本处理后,用户点击前两个链接时,如果安装了迅雷插件,浏览器就会唤起迅雷进行下载。