在 Django 中处理跨域场景下的自定义响应头(如Content-Disposition)时,需结合django-cors-headers中间件进行配置,避免响应头被拦截。以下是完整解决方案
在 Django 中处理跨域场景下的自定义响应头(如Content-Disposition)时,需结合django-cors-headers中间件进行配置,避免响应头被拦截。以下是完整解决方案:
一、核心配置:django-cors-headerssettings.py 设置
跨域响应头需在配置文件中统一声明,视图中手动设置会被中间件覆盖:
# settings.py
# 1. 安装应用
INSTALLED_APPS = [
# ...其他应用
'corsheaders', # 添加跨域中间件应用
]
# 2. 中间件顺序(必须放在首位)
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 跨域中间件置顶
'django.middleware.security.SecurityMiddleware',
# ...其他中间件(如 CSRF、Session 等)
]
# 3. 跨域关键配置
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", # 前端开发地址
"https://your-production-domain.com", # 生产环境域名
]
CORS_ALLOW_CREDENTIALS = True # 允许携带 cookies(如需)
# 4. 暴露自定义响应头(核心!前端需获取的头必须在此声明)
CORS_EXPOSE_HEADERS = [
'Content-Disposition', # 文件下载文件名头
'X-Custom-Header', # 其他自定义头(如有)
]
二、视图中设置响应头(无需手动暴露)
在视图中直接设置自定义响应头,不要手动添加Access-Control-Expose-Headers:
# views.py
from django.http import HttpResponse
from django.utils.http import urlquote
def export_file_view(request):
# 示例:生成 Excel 文件内容(伪代码)
file_content = generate_excel()
# 创建响应对象
response = HttpResponse(
file_content,
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
# 设置 Content-Disposition(文件名需编码处理中文)
filename = "审计日志.xlsx"
encoded_filename = urlquote(filename) # 编码中文文件名
response['Content-Disposition'] = (
f'attachment; '
f'filename="{filename}"; ' # 兼容旧浏览器
f'filename*=UTF-8\'\'{encoded_filename}' # 标准编码格式
)
# 添加其他自定义头(如需)
response['X-Custom-Header'] = 'custom-value'
return response
三、前端 Axios 请求示例
确保请求时设置responseType: 'blob',并从响应头中提取Content-Disposition:
async function downloadFile() {
try {
const response = await axios.get('/api/export-file/', {
responseType: 'blob', // 必须设置为 blob 类型
withCredentials: true, // 如需携带 cookies(对应 CORS_ALLOW_CREDENTIALS: True)
});
// 从响应头获取 Content-Disposition
const contentDisposition = response.headers['content-disposition'];
let filename = 'default.xlsx';
// 解析文件名(处理编码和兼容性)
if (contentDisposition) {
const match = contentDisposition.match(/filename*=UTF-8''(.+)/);
if (match) filename = decodeURIComponent(match[1]);
}
// 创建下载链接
const url = URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
// 清理资源
link.remove();
URL.revokeObjectURL(url);
} catch (error) {
console.error('下载失败:', error);
}
}
四、验证与排查
1. 检查响应头:
在浏览器Network面板中查看请求响应头,确认:
Access-Control-Expose-Headers: Content-Disposition, X-Custom-Header
Content-Disposition: attachment; filename="审计日志.xlsx"; filename*=UTF-8''%E5%AE%A1%E8%AE%A1%E6%97%A5%E5%BF%97.xlsx
2. 常见问题:
o 中间件顺序错误:CorsMiddleware未放在首位 → 导致跨域头不生效。
o 文件名编码问题:未使用urlquote编码中文 → 文件名乱码。
o CORS_EXPOSE_HEADERS 遗漏:自定义头未添加到配置 → 前端无法获取。
总结
跨域场景下,自定义响应头需通过django-cors-headers的CORS_EXPOSE_HEADERS配置暴露,视图中仅需设置业务相关头(如Content-Disposition)。此方案确保前端能正确获取响应头,实现文件下载等功能。