django实现大文件的断点续传(暂停/继续下载)

1. 实现方式

功能基于django.views.static.serve实现,实现的关键点是:

        a. response中增加'Content-Range'、'Cache-Control'的参数

        b. 根据不同的情况为response设置不同的status

        c. 根据HTTP_RANGE对读取文件时的起始位置进行设置

2. 视图函数

文件位置:myproject/views_file.py

import re
import os
import stat
import mimetypes
import posixpath
from django.utils._os import safe_join
from django.utils.http import http_date
from django.views.static import was_modified_since
from django.http import Http404, FileResponse, HttpResponseNotModified


# 基于django.views.static.serve实现,支持大文件的断点续传(暂停/继续下载)
def get_file_response(request, path, document_root=None):
    # 防止目录遍历漏洞
    path = posixpath.normpath(path).lstrip('/')
    fullpath = safe_join(document_root, path)
    if os.path.isdir(fullpath):
        raise Http404('Directory indexes are not allowed here.')
    if not os.path.exists(fullpath):
        raise Http404('"%(path)s" does not exist' % {'path': fullpath})

    statobj = os.stat(fullpath)

    # 判断下载过程中文件是否被修改过
    if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                              statobj.st_mtime, statobj.st_size):
        return HttpResponseNotModified()

    # 获取文件的content_type
    content_type, encoding = mimetypes.guess_type(fullpath)
    content_type = content_type or 'application/octet-stream'

    # 计算读取文件的起始位置
    start_bytes = re.search(r'bytes=(\d+)-', request.META.get('HTTP_RANGE', ''), re.S)
    start_bytes = int(start_bytes.group(1)) if start_bytes else 0

    # 打开文件并移动下标到起始位置,客户端点击继续下载时,从上次断开的点继续读取
    the_file = open(fullpath, 'rb')
    the_file.seek(start_bytes, os.SEEK_SET)

    # status=200表示下载开始,status=206表示下载暂停后继续,为了兼容火狐浏览器而区分两种状态
    # 关于django的response对象,参考:https://www.cnblogs.com/scolia/p/5635546.html
    # 关于response的状态码,参考:https://www.cnblogs.com/DeasonGuan/articles/Hanami.html
    # FileResponse默认block_size = 4096,因此迭代器每次读取4KB数据
    response = FileResponse(the_file, content_type=content_type, status=206 if start_bytes > 0 else 200)

    # 'Last-Modified'表示文件修改时间,与'HTTP_IF_MODIFIED_SINCE'对应使用,参考:https://www.jianshu.com/p/b4ecca41bbff
    response['Last-Modified'] = http_date(statobj.st_mtime)

    # 这里'Content-Length'表示剩余待传输的文件字节长度
    if stat.S_ISREG(statobj.st_mode):
        response['Content-Length'] = statobj.st_size - start_bytes
    if encoding:
        response['Content-Encoding'] = encoding

    # 'Content-Range'的'/'之前描述响应覆盖的文件字节范围,起始下标为0,'/'之后描述整个文件长度,与'HTTP_RANGE'对应使用
    # 参考:http://liqwei.com/network/protocol/2011/886.shtml
    response['Content-Range'] = 'bytes %s-%s/%s' % (start_bytes, statobj.st_size - 1, statobj.st_size)

    # 'Cache-Control'控制浏览器缓存行为,此处禁止浏览器缓存,参考:https://blog.csdn.net/cominglately/article/details/77685214
    response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    return response

3. 路由配置

文件位置:myproject/urls.py


from django.urls import re_path
from django.conf import settings
from myproject import views_file

# MEDIA_ROOT是要下载的文件的存储路径的前半段,下面的配置中'files/.*'匹配到的路径则是后半段,两者合并就是要下载的文件的完整路径
urlpatterns = [re_path(r'^download/(files/.*)$', views_file.get_file_response, {'document_root': settings.MEDIA_ROOT})]

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Vue是一种流行的JavaScript框架,用于构建用户界面。Django是一个用于构建Web应用程序的Python框架。使用这两种框架可以很容易地实现文件下载的功能。 首先,在Django中,你需要创建一个视图函数来处理文件下载的请求。你可以使用Python的内置模块`open`来打开文件,并将其内容发送给浏览器。具体代码如下: ```python from django.http import FileResponse import os def download_file(request): file_path = '/path/to/your/file.pdf' # 文件路径 file_name = os.path.basename(file_path) # 获取文件名 response = FileResponse(open(file_path, 'rb'), as_attachment=True) response['Content-Disposition'] = f'attachment; filename="{file_name}"' return response ``` 在Vue中,你可以创建一个按钮或链接来触发文件下载的请求。使用`axios`库来发起HTTP请求并下载文件。具体代码如下: ```javascript <template> <div> <button @click="downloadFile">下载文件</button> </div> </template> <script> import axios from 'axios'; export default { methods: { downloadFile() { axios({ url: 'http://your-api-url/download', method: 'GET', responseType: 'blob', // 必须设置为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(); }); } } } </script> ``` 以上是一个简单的示例,演示了如何在Vue和Django实现文件下载的功能。当用户点击“下载文件”按钮时,Vue将发送一个HTTP请求到Django后端,后端会返回文件的内容,然后前端利用Blob对象创建一个URL,最终通过创建一个a标签实现文件下载
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值