eagleye

在 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. 常见问题

中间件顺序错误CorsMiddleware未放在首位 → 导致跨域头不生效。

文件名编码问题:未使用urlquote编码中文 → 文件名乱码。

CORS_EXPOSE_HEADERS 遗漏:自定义头未添加到配置 → 前端无法获取。

总结

跨域场景下,自定义响应头需通过django-cors-headers的CORS_EXPOSE_HEADERS配置暴露,视图中仅需设置业务相关头(如Content-Disposition)。此方案确保前端能正确获取响应头,实现文件下载等功能。

 

posted on 2025-07-31 22:44  GoGrid  阅读(16)  评论(0)    收藏  举报

导航