You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过AJAX GET请求实现Django后端CSV文件下载?

解决AJAX请求Django CSV响应无法触发下载的问题

我之前也踩过这个坑!首先得说清楚:AJAX本身并不适合直接处理文件下载——因为它会把服务器响应留在内存里,没法触发浏览器自带的下载行为。而且你现在的请求总是进error回调,大概率是因为Django返回的是attachment类型的响应,AJAX默认的文本解析方式处理不了这种流数据。

为什么当前方案不行?

当Django返回Content-Disposition: attachment的响应时,浏览器的默认行为是弹出下载框,但AJAX会拦截这个响应,尝试把它当成普通文本/JSON解析,一旦解析失败就会进入error回调,这就是你碰到的问题。

解决方案

方案1:放弃AJAX,直接触发下载(最简单)

如果你的下载请求不需要前置的AJAX验证或数据处理,直接跳转URL是最省心的办法——浏览器会自动处理attachment响应,弹出下载框:

$(document).ready(function () {
    $('#download-grades').on('click', function (event) {
        event.preventDefault();
        var grades_csv_url = $(event.target).data().url;
        
        // 方法1:直接跳转至下载URL
        window.location.href = grades_csv_url;
        
        // 方法2:创建隐藏a标签模拟点击(适合需要自定义文件名的场景)
        // const downloadLink = document.createElement('a');
        // downloadLink.href = grades_csv_url;
        // downloadLink.download = '学生成绩.csv'; // 手动指定下载文件名
        // document.body.appendChild(downloadLink);
        // downloadLink.click();
        // document.body.removeChild(downloadLink);
    });
});

方案2:用AJAX处理响应后手动触发下载(适合需要前置逻辑的场景)

如果必须用AJAX(比如要先验证用户权限、处理一些前端逻辑),那我们可以让AJAX以blob类型接收响应,然后手动创建下载链接触发浏览器下载:

第一步:优化Django视图(指定文件名)

先给响应的Content-Disposition加上文件名,方便用户下载时识别:

from django.http import HttpResponse
import csv
from io import StringIO

def download_student_grades(request):
    students = # 这里替换成你的学生数据查询逻辑
    buf = StringIO()
    writer = csv.writer(buf)
    
    # 先写入表头
    writer.writerow(get_header())
    # 批量写入学生数据
    for student in students:
        writer.writerow([student.id, student.name, student.marks])
    
    response = HttpResponse(buf.getvalue(), content_type='text/csv')
    # 指定下载文件名,浏览器会自动识别
    response['Content-Disposition'] = 'attachment; filename="学生成绩.csv"'
    return response

第二步:修改AJAX代码

重点是设置xhrFields.responseType = 'blob',让AJAX正确接收二进制流数据,然后手动创建下载链接:

$(document).ready(function () {
    $('#download-grades').on('click', function (event) {
        event.preventDefault();
        var grades_csv_url = $(event.target).data().url;
        
        $.ajax({
            url: grades_csv_url,
            type: 'GET',
            xhrFields: {
                responseType: 'blob' // 关键:告诉AJAX接收二进制blob数据
            },
            success: function (response) {
                // 从响应头中提取文件名(如果Django设置了的话)
                const disposition = this.getResponseHeader('Content-Disposition');
                let filename = '学生成绩.csv';
                if (disposition) {
                    const filenameMatch = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
                    if (filenameMatch && filenameMatch[1]) {
                        filename = filenameMatch[1].replace(/['"]/g, '');
                    }
                }
                
                // 创建临时URL和下载链接
                const blobUrl = window.URL.createObjectURL(response);
                const downloadLink = document.createElement('a');
                downloadLink.href = blobUrl;
                downloadLink.download = filename;
                
                // 触发点击下载
                document.body.appendChild(downloadLink);
                downloadLink.click();
                
                // 清理临时资源
                window.URL.revokeObjectURL(blobUrl);
                document.body.removeChild(downloadLink);
            },
            error: function (jqXHR) {
                console.log('下载失败:', jqXHR.responseText);
            }
        });
    });
});

总结

  • 如果没有特殊需求,优先用方案1,代码简洁还不容易出问题;
  • 如果必须用AJAX,记得设置responseType: 'blob',并手动处理下载逻辑。

内容的提问来源于stack exchange,提问作者A.J.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:52:32