ajax datatype_关于Django+Ajax实现文件下载的几个小问题

投稿说明:如何向本公众号投稿? 最近在利用Django进行web后端开发。众所周知,Django是一个基于MTV的开发框架,与flask不同,Django自身带有成熟的ORM框架,因此在数据库的连接以及数据的查询等处理操作上非常方便。 但是,这两天在实现文件下载功能上却遇到了一些小问题。

1

def download(request):if request.method == "GET":
        id = request.GET["id"]
        file_path = "Themepark/static/file/" + id + ".xlsx"try:
            response = FileResponse(open(file_path, "rb"))
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Disposition'] = 'attachment;filename="{}"'.format(os.path.basename(file_path))return responseexcept Exception:raise Http404elif request.method == "POST":pass
首先是Django的后端代码。根据官方的API,文件传送一共可以使用三种response对象。其中最常见的HttpResponse在大文件的传送上相对来说更加占用服务器的资源,因此在 面对大批量数据传送时通常采用StreamHttpResponse或FileResponse 。在这里我采用了FileResponse。请求方法使用的是GET请求,一切都按照官方的API编写。
function download() {var filelist = Array();
    $('input:checked').each(function () {var brother = $(this).parentsUntil(".selected").next().children();var href = brother.attr("href");if (href) {
            filelist.push(brother.attr("href"));
        }
    });var temp, link, json;for (var i = 0; i         temp = filelist[i].split("?");
        link = temp[0] + "/download?" + temp[1];
    }
    json = {url: link,type: "get",data: {},dataType: "json",success: function (resText, statusText) {console.log(resText);
        },error: console.log("error")
    };
    $.ajax(json);
}
其次是Ajax代码。 关于Ajax异步请求,主要是为了在页面不进行刷新的情况下进行对后端服务器的请求。 由于整体采用的是jQuery框架,因此Ajax请求同样使用封装好的$.ajax()函数一步到位。回调函数的作用是正确接收返回值时在控制台输出返回值,若发生错误则直接打印error。 但就是这里出现了未知的错误:
[19/Feb/2020 05:13:08] "GET /themepark/download?id=7&csrfmiddlewaretoken=%7B%7B%20csrf_token%20%7D%7D HTTP/1.1" 301 0
[19/Feb/2020 05:13:08] "GET /themepark/download/?id=7&csrfmiddlewaretoken=%7B%7B%20csrf_token%20%7D%7D HTTP/1.1" 200 5248
       后端的终端信息表明GET请求已经发送成功,然而前端的控制台却打印出error字样,说明在前后端交互过程中出现了不可预料的错误。 我在这个错误卡了几个小时,却丝毫未得到进展。

2

    var temp, link;function send_ajax() {for (var i = 0; i             temp = filelist[i].split("?");
            link = temp[0] + "/download?" + temp[1];var xhr = new XMLHttpRequest();
            xhr.open("get", link, true);
            xhr.responseType = "blob";
            xhr.onreadystatechange = function () {if(xhr.readyState==4 && xhr.status == 200){console.log("success");
                }else{console.log("error");
                }
            }}
            xhr.send();
        }
在翻阅大量资料后问题仍未能得到解决,但这时看到一篇名为《ajax 请求二进制流 图片 文件  XMLHttpRequest 请求并处理二进制流数据 之最佳实践》的博客有点意思(https://www.cnblogs.com/cdemo/p/5225848.html)。其中作者提到,在查阅了jQuery的官方文档后发现, jQuery所支持的dataType是没有二进制字节流的,也就是说jQuery所发起的Ajax传输的字节流都将转换为字符串。 因此想要利用Ajax进行字节流传输应该要使用原生的JavaScript。 这时我已经大概知道哪里存在问题了,在利用jQuery写Ajax请求时,我返回的dataType写的是json,然而从后端传送回来的是二进制字节流,与预期的dataType存在冲突,因此会调用error时的回调函数。既然知道问题所在,我立马将代码改成了上述利用原生js写出来的Ajax。

3

      此时前端控制台确实打印出了success字样,可是又面临一个新问题:如何保存传输过来的二进制字节流?同样,在《关于Ajax无法下载文件到浏览器本地的问题》中有提到(https://blog.csdn.net/duansamve/article/details/84075021): 通过Ajax下载文件的这种方式本来就是禁止的。出于安全因素的考虑,javascript是不能够保存文件到本地的,所以ajax考虑到了这点,只是接受xml,ajax,json格式的返回值。
这一段话说明,直接在js中进行文件的下载操作是不可行的,但是js的作用有DOM操作这种东西,通过超链接进行下载是允许的,如果利用js生成a标签再模拟点击,不就实现了下载功能?
    var temp, link;function send_ajax() {for (var i = 0; i             temp = filelist[i].split("?");
            link = temp[0] + "/download?" + temp[1];var xhr = new XMLHttpRequest();
            xhr.open("get", link, true);
            xhr.responseType = "blob";
            xhr.onreadystatechange = function () {if(xhr.readyState==4 && xhr.status == 200){var blob = new Blob([xhr.response]);var a = document.createElement('a');
                    a.download = 'data.xlsx';
                    a.href=window.URL.createObjectURL(blob);
                    a.click();
                }else{console.log("error");
                }
            }}
            xhr.send();
        }
将接收到二进制字节流后的操作改成上述所示,就大功告成了!      试着点击下载一下,确实没毛病!因此问题关于Django + Ajax实现文件下载的问题也就都解决了。 5323e3fb6d8682ec79165aaa78ccf03a.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值