当你在使用Vue.js 和 Django开发网站时,你经常会遇到需要用户下载文件的情况。下面是两个可以帮助你实现这个功能的示例:
示例一:Vue + Django 实现下载文件
Vue 部分
假设你在 Vue.js 2.x 中,首先你需要一个下载接口在 Vue 组件中:
downloadFile() {
const url = 'http://example.com/api/files/1/download';
axios({
url: url,
method: 'GET',
responseType: 'blob',
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
},
url
包含你要从服务器中下载的文件的地址。在这个例子中,我们从具有ID 1的文件中下载文件。
axios
是一个常见的 JavaScript 库,用于处理 HTTP 请求。这个函数的实现中使用了responseType: 'blob'参数,因为服务器会返回二进制数据。
一旦响应成功返回,我们可以将数据转为URL object、创建一个链接并用于 Document 对象。
该链接上的 download 的属性告诉浏览器该文件的名称。
Django部分
假设你有一个文件下载API视图:
from django.http import HttpResponse
from django.views.generic import View
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
class DownloadFileView(View):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
file_id = self.kwargs['file_id']
#从数据库中获取具有ID为file_id的文件的路径
# ...
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type='application/octet-stream')
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
content_type
告诉浏览器何种文件类型,因此这必须根据你的应用程序进行设置。在这里,我将它设置为 application/octet-stream
,这是一个通用的内容类型。Content-Disposition
标头使你可以强制浏览器打开保存对话框,而不是在浏览器中打开文件。
示例 2:使用 Vue 和 Django 3.1 来下载大型文件
Vue 部分的代码和上面一样。这个示例是关于如何将从数据库中读取的大文件下载到浏览器的示例。
Django 部分
from django.http import StreamingHttpResponse
from wsgiref.util import FileWrapper
from django.views.generic import View
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
class DownloadLargeFileView(View):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
file_id = self.kwargs['file_id']
#获取具有ID file_id的文件
#...
file_path = get_file_path(file_id)
transfer_encoding = request.META.get('HTTP_TRANSFER_ENCODING')
content_length = os.path.getsize(file_path)
fileobject = FileWrapper(open(file_path, 'rb'))
if transfer_encoding and transfer_encoding == 'chunked':
response = StreamingHttpResponse(
iter(lambda: fileobject.read(4096), b''),
content_type='application/octet-stream',
status=200,
)
response['Transfer-Encoding'] = 'chunked'
else:
response = HttpResponse(
content_type='application/octet-stream',
status=200,
)
response['Content-Length'] = content_length
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
response.streaming_content = iter(lambda: fileobject.read(4096), b'')
return response
这里的主要区别是使用 StreamingHttpResponse
与 FileWrapper
。在这里, 文件被打开,并传递给 FileWrapper
,这将返回一个迭代器。
此点请注意细节:这里设置分隔符 lambda 函数在取出每个块时自动运行,在收到时去往客户端。
最后,我们需要检查 HTTP Transfer-Encoding,并根据结果返回一个 StreamingHttpResponse
或HttpResponse
。
在 StreamingHttpResponse
中,使用迭代器读取并生成每个块,直到结束并安全关闭连接。
在 HttpResponse
中Content-Length
设置文件的大小,然后将整个文件读入内存。
注: 在文件大小超过 2.5 MB 的情况下,向浏览器推送数据时,设置 Transfer-Encoding: chunked,防止对方网站被暴力攻击阻塞(拒绝服务攻击)。
希望以上的示例可以帮助你继续开发你的 Vue.js + Django 应用程序,并成功地实现一个文件下载系统。
本文链接:https://my.lmcjl.com/post/19263.html
4 评论