一、问题背景
在前后端分离项目中,前端通过 AJAX 或 Fetch 请求接口时,发现无法获取响应头中的 Content-Disposition
(用于文件下载的文件名指定)但是在浏览器开发者工具的 Network 面板中,可以看到Content-Disposition
,就是取不到值。例如:
- 后端已设置
Content-Disposition: attachment; filename="test.txt"
- 前端尝试通过
response.headers['content-disposition']
获取时返回null
二、核心原因
1. CORS 默认隐藏非简单响应头
浏览器默认只允许前端访问有限的"简单响应头"(如 Cache-Control、Content-Type 等),而 Content-Disposition 等自定义响应头默认被隐藏。
2. 未显式暴露目标响应头
服务器虽设置了 Content-Disposition,但未通过 Access-Control-Expose-Headers 明确允许前端访问该头,导致前端无法读取。
三、解决方案
1. 后端配置 CORS,暴露目标响应头
原理
通过 Access-Control-Expose-Headers
指定允许前端访问的响应头。
实现示例
Spring Boot (Java)
java
response.setHeader("Content-Disposition", "attachment; filename=\"test.txt\"");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
Node.js (Express)
javascript
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'http://frontend-domain', // 或 '*' 允许所有域名
exposedHeaders: ['Content-Disposition'], // 关键配置
}));
app.get('/download', (req, res) => {
res.set('Content-Disposition', 'attachment; filename="test.txt"');
res.send('File content');
});
app.listen(3000);
Nginx 反向代理
nginx
server {
listen 80;
server_name your-domain.com;
location /api/ {
proxy_pass http://backend-server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
add_header Access-Control-Expose-Headers "Content-Disposition"; // 关键配置
}
}
2. 确保后端正确设置 Content-Disposition
示例
java
response.setHeader("Content-Disposition", "attachment; filename=\"test.txt\"");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
注意事项:
- 避免仅在本地调试时设置该头,需确保生产环境代码中也包含。
- 动态生成文件名的场景需注意特殊字符处理(如引号、空格等)。
3. 前端正确获取响应头
示例代码
javascript
// 使用 Fetch API 获取响应头并触发下载
fetch('https://api.example.com/download')
.then(response => {
// 获取 Content-Disposition 头
const disposition = response.headers['content-disposition'];
if (disposition && disposition.includes('attachment')) {
const filename = disposition.split('filename=')[1].replace(/["']/g, '');
return response.blob().then(blob => {
// 创建下载链接
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
});
}
return response.json(); // 处理其他情况
})
.catch(error => console.error('Error:', error));
五、验证步骤
- 直接访问接口 :在浏览器地址栏输入
http://localhost:8080/download
,应自动触发文件下载。 - 跨域请求测试 :将前端部署到其他域名(如
http://localhost:3000
),点击按钮触发下载。 - 检查响应头 :在浏览器开发者工具的 Network 面板中,确认响应头包含:
Access-Control-Expose-Headers: Content-Disposition
Content-Disposition: attachment; filename="test.txt"
六、常见问题排查
-
问题1 :前端仍然无法获取
Content-Disposition
解决 :检查后端是否真正配置了exposedHeaders
,代理服务器是否转发了该头。 -
问题2 :文件下载失败但接口返回正常
解决 :确保后端正确设置Content-Disposition
,且文件路径有效,前端请求时设置responseType: 'blob'
。 -
问题3 :下载文件无法打开
解决 :确保前端请求时设置responseType: 'blob'
。
通过以上配置,前端即可安全地获取 Content-Disposition
等自定义响应头,实现文件下载功能。