切换主题
📥 文件下载接口
本文档介绍文件下载相关的所有接口,支持多种下载方式和在线预览。
功能概述
文件下载接口提供了灵活的文件访问方式,支持:
- ✅ 多种下载方式(路径参数、查询参数)
- ✅ 自定义下载文件名
- ✅ 在线预览(图片、PDF等)
- ✅ 业务类型隔离
- ✅ 流式传输,支持大文件
下载流程
下载方式
方式对比
| 方式 | URL格式 | 适用场景 | 推荐度 |
|---|---|---|---|
| 路径参数 | /download/{业务类型}/{文件路径} | 标准下载,URL简洁 | ⭐⭐⭐⭐⭐ |
| 查询参数 | /download/{业务类型}?filePath=xxx | 特殊字符路径 | ⭐⭐⭐⭐ |
| 默认下载 | /download?filePath=xxx | 内部系统 | ⭐⭐⭐ |
接口说明
1️⃣ 路径参数下载(推荐)
通过URL路径指定业务类型和文件路径,URL更简洁直观。
接口信息
GET /download/{业务类型}/{文件路径}1
请求参数
| 参数名 | 位置 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
业务类型 | Path | String | 是 | 业务类型代码 | video |
文件路径 | Path | String | 是 | 文件存储路径 | 2024/08/25/file.mp4 |
fileName | Query | String | 否 | 自定义下载文件名 | 我的视频.mp4 |
请求示例
bash
# 基础下载
curl -O "http://localhost:9830/download/video/2024/08/25/23/abc123.mp4"
# 自定义文件名
curl -O "http://localhost:9830/download/video/2024/08/25/23/abc123.mp4?fileName=我的视频.mp4"1
2
3
4
5
2
3
4
5
javascript
// 直接下载
window.location.href = '/download/video/2024/08/25/23/abc123.mp4';
// 自定义文件名
const downloadUrl = '/download/video/2024/08/25/23/abc123.mp4?fileName='
+ encodeURIComponent('我的视频.mp4');
window.location.href = downloadUrl;1
2
3
4
5
6
7
2
3
4
5
6
7
html
<!-- 直接链接 -->
<a href="/download/video/2024/08/25/23/abc123.mp4" download>下载视频</a>
<!-- 自定义文件名 -->
<a href="/download/video/2024/08/25/23/abc123.mp4?fileName=我的视频.mp4" download>
下载视频
</a>
<!-- 在线预览(图片) -->
<img src="/download/image/2024/08/25/23/photo.jpg" alt="图片">
<!-- 在线预览(PDF) -->
<iframe src="/download/document/2024/08/25/23/doc.pdf" width="100%" height="600px"></iframe>1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
响应说明
成功响应:
- Status:
200 OK - Headers:
Content-Type: 根据文件类型自动设置Content-Disposition:inline或attachmentContent-Length: 文件大小
- Body: 文件二进制流
常见Content-Type:
| 文件类型 | Content-Type |
|---|---|
| 图片 (jpg/png) | image/jpeg, image/png |
application/pdf | |
| 视频 (mp4) | video/mp4 |
| 文档 (docx) | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
| 文本 (txt) | text/plain |
2️⃣ 查询参数下载
通过查询参数指定文件路径,适合路径包含特殊字符的场景。
接口信息
GET /download/{业务类型}?filePath={文件路径}1
请求参数
| 参数名 | 位置 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
业务类型 | Path | String | 是 | 业务类型代码 | document |
filePath | Query | String | 是 | 文件存储路径 | /2024/08/25/file.pdf |
fileName | Query | String | 否 | 自定义下载文件名 | 报告.pdf |
请求示例
bash
# 基础下载
curl -O "http://localhost:9830/download/document?filePath=/2024/08/25/23/report.pdf"
# 自定义文件名
curl -O "http://localhost:9830/download/document?filePath=/2024/08/25/23/report.pdf&fileName=报告.pdf"1
2
3
4
5
2
3
4
5
javascript
// 使用fetch下载
async function downloadFile(businessType, filePath, fileName) {
const params = new URLSearchParams({
filePath: filePath,
...(fileName && { fileName })
});
const response = await fetch(`/download/${businessType}?${params}`);
const blob = await response.blob();
// 创建下载链接
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName || filePath.split('/').pop();
a.click();
window.URL.revokeObjectURL(url);
}
// 使用示例
downloadFile('document', '/2024/08/25/23/report.pdf', '报告.pdf');1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
3️⃣ 默认下载接口
不区分业务类型的通用下载接口,适用于内部系统。
接口信息
GET /download?filePath={文件路径}1
安全提醒
此接口不进行业务类型校验,建议:
- 仅在内网环境使用
- 添加额外的权限控制
- 不要在生产环境直接暴露
请求参数
| 参数名 | 位置 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|---|
filePath | Query | String | 是 | 文件存储路径 | /2024/08/25/file.pdf |
fileName | Query | String | 否 | 自定义下载文件名 | 文件.pdf |
使用示例
场景1: 图片在线预览
html
<!-- 直接使用img标签 -->
<img src="/download/image/2024/08/25/23/photo.jpg"
alt="照片"
style="max-width: 100%;">
<!-- 使用背景图 -->
<div style="background-image: url('/download/image/2024/08/25/23/bg.jpg');">
</div>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
场景2: PDF在线预览
html
<!-- 使用iframe -->
<iframe src="/download/document/2024/08/25/23/report.pdf"
width="100%"
height="800px"
frameborder="0">
</iframe>
<!-- 使用embed -->
<embed src="/download/document/2024/08/25/23/report.pdf"
type="application/pdf"
width="100%"
height="800px">1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
场景3: 视频播放
html
<!-- 使用video标签 -->
<video controls width="100%">
<source src="/download/video/2024/08/25/23/movie.mp4" type="video/mp4">
您的浏览器不支持视频播放
</video>1
2
3
4
5
2
3
4
5
场景4: 文件下载(带进度)
javascript
async function downloadWithProgress(url, fileName) {
const response = await fetch(url);
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
const chunks = [];
while(true) {
const {done, value} = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
// 更新进度
const progress = (receivedLength / contentLength * 100).toFixed(1);
console.log(`下载进度: ${progress}%`);
updateProgressBar(progress);
}
// 合并chunks并下载
const blob = new Blob(chunks);
const downloadUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(downloadUrl);
}
// 使用示例
downloadWithProgress(
'/download/video/2024/08/25/23/large-video.mp4',
'大视频.mp4'
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
场景5: 批量下载
javascript
async function batchDownload(files) {
for (const file of files) {
const { businessType, filePath, fileName } = file;
const url = `/download/${businessType}/${filePath}?fileName=${encodeURIComponent(fileName)}`;
// 创建隐藏的iframe进行下载
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
// 延迟避免浏览器阻止
await new Promise(resolve => setTimeout(resolve, 500));
}
}
// 使用示例
batchDownload([
{ businessType: 'document', filePath: '2024/08/25/23/file1.pdf', fileName: '文件1.pdf' },
{ businessType: 'document', filePath: '2024/08/25/23/file2.pdf', fileName: '文件2.pdf' },
{ businessType: 'document', filePath: '2024/08/25/23/file3.pdf', fileName: '文件3.pdf' }
]);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
最佳实践
✅ 推荐做法
1. 接口选择
javascript
// ✅ 推荐:使用路径参数(URL简洁)
const url = `/download/video/2024/08/25/23/movie.mp4`;
// ⚠️ 备选:查询参数(特殊字符路径)
const url = `/download/video?filePath=${encodeURIComponent(complexPath)}`;
// ❌ 不推荐:默认接口(生产环境)
const url = `/download?filePath=/2024/08/25/23/file.pdf`;1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2. 文件名处理
javascript
// ✅ 正确:URL编码中文文件名
const fileName = encodeURIComponent('我的文档.pdf');
const url = `/download/document/2024/08/25/23/abc.pdf?fileName=${fileName}`;
// ❌ 错误:不编码中文
const url = `/download/document/2024/08/25/23/abc.pdf?fileName=我的文档.pdf`;1
2
3
4
5
6
2
3
4
5
6
3. 错误处理
javascript
async function safeDownload(url, fileName) {
try {
const response = await fetch(url);
if (!response.ok) {
if (response.status === 404) {
throw new Error('文件不存在');
} else if (response.status === 403) {
throw new Error('无访问权限');
} else {
throw new Error(`下载失败: ${response.status}`);
}
}
const blob = await response.blob();
// ... 下载逻辑
} catch (error) {
console.error('下载错误:', error);
alert(error.message);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
4. 大文件下载
javascript
// ✅ 使用流式下载,避免内存溢出
async function downloadLargeFile(url, fileName) {
const response = await fetch(url);
const reader = response.body.getReader();
// 使用流式API
const stream = new ReadableStream({
start(controller) {
function push() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
return;
}
controller.enqueue(value);
push();
});
}
push();
}
});
const blob = await new Response(stream).blob();
// ... 下载逻辑
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
⚠️ 注意事项
| 项目 | 说明 |
|---|---|
| 路径安全 | 避免路径遍历攻击,不要使用 .. 等特殊字符 |
| 文件名编码 | 中文文件名必须进行URL编码 |
| CORS | 跨域下载需要配置CORS响应头 |
| 缓存控制 | 根据文件类型设置合适的缓存策略 |
| 大文件 | 大文件建议使用流式下载,避免内存问题 |
| 权限控制 | 生产环境建议添加下载权限验证 |
| 日志记录 | 记录下载日志,便于审计和问题排查 |
错误码说明
| HTTP状态码 | 说明 | 常见原因 | 解决方案 |
|---|---|---|---|
200 | 成功 | - | - |
400 | 请求参数错误 | 缺少必填参数、参数格式错误 | 检查请求参数 |
403 | 无访问权限 | 业务类型不匹配、权限不足 | 确认业务类型和权限配置 |
404 | 文件不存在 | 文件路径错误、文件已删除 | 检查文件路径是否正确 |
500 | 服务器错误 | 存储服务异常、配置错误 | 查看服务器日志 |
常见问题
Q: 如何实现文件下载而不是在线预览?
A: 有两种方式:
- 使用HTML5的download属性:
html
<a href="/download/document/2024/08/25/23/file.pdf" download>下载文件</a>1
- 服务端设置Content-Disposition为attachment(需要后端支持)
Q: 下载大文件时如何显示进度?
A: 使用Fetch API的流式读取:
javascript
const response = await fetch(url);
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
while(true) {
const {done, value} = await reader.read();
if (done) break;
receivedLength += value.length;
const progress = (receivedLength / contentLength * 100).toFixed(1);
updateProgress(progress);
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Q: 如何处理中文文件名?
A: 使用URL编码:
javascript
const fileName = '我的文档.pdf';
const encodedName = encodeURIComponent(fileName);
const url = `/download/document/path/to/file.pdf?fileName=${encodedName}`;1
2
3
2
3
Q: 如何实现断点续传下载?
A: 使用HTTP Range请求头:
javascript
const response = await fetch(url, {
headers: {
'Range': `bytes=${startByte}-${endByte}`
}
});1
2
3
4
5
2
3
4
5
注意:需要服务端支持Range请求。
Q: 跨域下载如何处理?
A: 需要服务端配置CORS响应头:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Range1
2
3
2
3
或者使用代理服务器转发请求。