- 下载文件:这是最常见的需求,比如下载 PDF、图片、CSV、Excel 文档等。
- 下载代码:主要用于代码编辑器或在线 IDE,让用户可以下载当前编辑的代码文件。
下面我将详细介绍这两种场景下的常用方法和代码示例。

(图片来源网络,侵删)
下载文件
实现文件下载主要有三种主流方法,各有优缺点。
方法 1:使用 <a> 标签的 download 属性(最常用、最简单)
这是最推荐、最现代的方法,它利用了 HTML5 的标准属性,简单直接。
原理:创建一个 <a> 标签,将文件的 URL 设置为 href 属性,然后将 download 属性设置为你希望下载的文件名,当用户点击这个链接时,浏览器就会下载文件,而不是在新标签页中打开它。
优点:

(图片来源网络,侵删)
- 简单易用:代码量少,易于理解。
- 无需服务器交互:可以直接下载任何同源或允许跨域的 URL 资源。
- 原生支持:所有现代浏览器都支持。
缺点:
- 同源策略限制:如果文件 URL 与当前页面不同源,且服务器没有设置正确的 CORS(跨域资源共享)头,则会因为安全策略而失败。
- 无法获取下载进度:这是一个“一次性”操作,无法监听下载过程中的状态(如开始、进度、完成、失败)。
代码示例:
/**
* 使用 a 标签下载文件
* @param {string} fileUrl - 文件的 URL
* @param {string} fileName - 下载时显示的文件名
*/
function downloadFile(fileUrl, fileName) {
// 创建一个临时的 a 标签
const link = document.createElement('a');
link.href = fileUrl;
link.download = fileName || 'download'; // 如果没有提供文件名,则使用默认名
// 将 a 标签添加到 body 中
document.body.appendChild(link);
// 模拟点击 a 标签
link.click();
// 点击后移除 a 标签,清理 DOM
document.body.removeChild(link);
}
// --- 使用示例 ---
// 下载一个在线的图片
downloadFile('https://picsum.photos/800/600', 'random-image.jpg');
// 下载一个同目录下的 PDF
// downloadFile('/files/sample.pdf', 'my-document.pdf');
方法 2:使用 Blob 和 URL.createObjectURL(最灵活,可处理动态数据)
当你需要下载由 JavaScript 动态生成的内容(如 JSON 数据、CSV 文件、Canvas 图像等)时,这个方法非常强大。
原理:

(图片来源网络,侵删)
- 将你的数据(字符串、ArrayBuffer 等)转换成一个
Blob对象。Blob是一个表示二进制数据的文件对象。 - 使用
URL.createObjectURL()方法为这个Blob对象创建一个临时的下载链接。 - 像方法 1 一样,创建一个
<a>标签并触发点击。
优点:
- 灵活性极高:可以处理任何能在 JavaScript 中表示的数据。
- 无需服务器:完全在前端生成文件并下载。
- 可以处理大文件:通过
Blob的分块处理,可以优化内存。
缺点:
- 代码比方法 1 稍复杂。
- 同样无法获取原生下载进度。
代码示例:
/**
* 使用 Blob 下载动态生成的内容
* @param {string} content - 文件内容
* @param {string} fileName - 下载时显示的文件名
* @param {string} mimeType - 文件的 MIME 类型,如 'text/plain', 'application/json'
*/
function downloadWithBlob(content, fileName, mimeType) {
// 1. 创建 Blob 对象
const blob = new Blob([content], { type: mimeType });
// 2. 创建临时下载链接
const url = URL.createObjectURL(blob);
// 3. 创建 a 标签并触发点击
const link = document.createElement('a');
link.href = url;
link.download = fileName;
document.body.appendChild(link);
link.click();
// 4. 清理:移除 a 标签并释放 URL 对象
document.body.removeChild(link);
URL.revokeObjectURL(url); // 释放内存,非常重要!
}
// --- 使用示例 ---
// 1. 下载 JSON 文件
const jsonData = { name: '张三', age: 30, city: '北京' };
downloadWithBlob(JSON.stringify(jsonData, null, 2), 'user-data.json', 'application/json');
// 2. 下载 CSV 文件
const csvData = '姓名,年龄,城市\n李四,25,上海\n王五,28,广州';
downloadWithBlob(csvData, 'users.csv', 'text/csv');
// 3. 下载 Canvas 生成的内容
// const canvas = document.getElementById('myCanvas');
// const canvasDataUrl = canvas.toDataURL('image/png');
// // 注意:这里需要将 Data URL 转换为 Blob
// fetch(canvasDataUrl)
// .then(res => res.blob())
// .then(blob => {
// const url = URL.createObjectURL(blob);
// const link = document.createElement('a');
// link.href = url;
// link.download = 'canvas-image.png';
// link.click();
// URL.revokeObjectURL(url);
// });
方法 3:通过后端 API 下载(最可靠,适合需要权限或大文件)
当文件需要用户登录后才能访问、文件非常大或者需要复杂的业务逻辑(如数据库查询后生成)时,必须通过后端 API 来处理。
原理:
- 前端 JavaScript 发起一个网络请求(通常是
GET或POST)到后端的一个 API 端点。 - 后端处理请求,从数据库或文件系统读取文件,并将其作为 HTTP 响应体返回。
- 后端需要在响应头中设置
Content-Disposition: attachment; filename="...",这会告诉浏览器这是一个需要下载的附件。 - 前端接收到这个响应后,可以创建一个
<a>标签,将href设置为这个 API 的 URL,并触发点击。
优点:
- 安全性高:可以验证用户身份,确保只有授权用户才能下载。
- 适合大文件:后端有成熟的流式传输机制,可以避免一次性将大文件加载到内存。
- 功能强大:可以在后端进行任何复杂的处理。
缺点:
- 需要后端配合:必须有一个后端服务来处理文件。
- 用户体验稍差:需要一个网络请求,速度取决于服务器和用户网络。
前端代码示例:
/**
* 通过 API 下载文件
* @param {string} apiUrl - 后端 API 的 URL
* @param {string} fileName - 下载时显示的文件名 (可选,后端也可以提供)
*/
function downloadViaApi(apiUrl, fileName) {
// 创建一个临时的 a 标签
const link = document.createElement('a');
link.href = apiUrl;
// 如果后端没有在响应头中提供文件名,可以在这里指定一个默认的
// 但最好让后端通过 Content-Disposition 头来提供
if (fileName) {
link.download = fileName;
}
// 触发点击
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// --- 使用示例 ---
// 假设后端有一个 /api/export/invoices 接口,用于导出发票
// downloadViaApi('/api/export/invoices', 'invoices-2025.zip');
后端(Node.js/Express)代码示例:
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
app.get('/api/download/sample', (req, res) => {
const filePath = path.join(__dirname, 'files', 'sample.pdf');
const fileName = 'sample-document.pdf';
// 检查文件是否存在
if (fs.existsSync(filePath)) {
// 设置响应头,告诉浏览器这是一个附件,并指定文件名
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
res.setHeader('Content-Type', 'application/pdf'); // 设置正确的 MIME 类型
// 使用流来发送文件,避免内存溢出
const fileStream = fs.createReadStream(filePath);
fileStream.pipe(res);
} else {
res.status(404).send('File not found');
}
});
app.listen(3000, () => console.log('Server running on port 3000'));
下载代码
这通常用于在线代码编辑器(如 CodePen, JSFiddle, StackBlitz),实现逻辑和 方法 2(Blob) 非常相似,因为代码内容是动态生成的。
核心逻辑:
- 获取代码编辑器中的文本内容。
- 确定文件的类型(如
.js,.html,.css)。 - 使用
Blob和URL.createObjectURL创建下载链接并触发下载。
代码示例(以一个简单的文本域为例):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">代码下载示例</title>
</head>
<body>
<h2>在线代码编辑器</h2>
<textarea id="code-editor" style="width: 100%; height: 200px; font-family: monospace;">
// 这是一个 JavaScript 示例
function hello() {
console.log('Hello, World!');
}
hello();
</textarea>
<div>
<button onclick="downloadCode('js')">下载 .js 文件</button>
<button onclick="downloadCode('html')">下载 .html 文件</button>
<button onclick="downloadCode('css')">下载 .css 文件</button>
</div>
<script>
function downloadCode(fileType) {
const editor = document.getElementById('code-editor');
const content = editor.value;
let mimeType, fileExtension;
switch(fileType) {
case 'js':
mimeType = 'application/javascript';
fileExtension = 'js';
break;
case 'html':
mimeType = 'text/html';
fileExtension = 'html';
// 为了演示,我们简单地把 JS 代码包裹进 HTML 结构中
content = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">My Code</title>
</head>
<body>
<script>
${content}
</script>
</body>
</html>`;
break;
case 'css':
mimeType = 'text/css';
fileExtension = 'css';
break;
default:
mimeType = 'text/plain';
fileExtension = 'txt';
}
const fileName = `my-code.${fileExtension}`;
// 使用 Blob 方法
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
</script>
</body>
</html>
总结与选择建议
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
<a> 标签 download |
下载静态文件(图片、PDF等),文件与页面同源或已配置 CORS。 | 最简单,无需服务器交互,原生支持。 | 受 CORS 限制,无法获取下载进度。 |
Blob + createObjectURL |
下载动态生成的内容(JSON, CSV, Canvas 图像等)。 | 最灵活,完全前端实现,可处理任何数据。 | 代码稍复杂,无法获取原生下载进度。 |
| 后端 API | 下载需要权限、大文件或复杂逻辑生成的文件。 | 最安全可靠,适合企业级应用。 | 依赖后端,用户体验稍差。 |
Blob (代码下载) |
在线代码编辑器,下载动态编辑的代码。 | 灵活,用户体验好。 | 与 Blob 方法 2 相同。 |
选择建议:
- 如果只是下载一个静态文件,直接用 方法 1。
- 如果文件内容是 JS 动态生成的,用 方法 2。
- 如果文件涉及用户登录、权限或数据查询,用 方法 3。
- 如果是下载代码编辑器里的内容,用 方法 2 的变种。
