怎样在Python Flask应用中实现断点续传的大文件下载?

酷强同学_7886

酷强同学_7886

2026-07-17

646人浏览

原创

flask需手动解析range头并返回206响应:提取bytes范围、校验合法性、设置content-range;不能用send_file或send_from_directory,须以rb模式打开文件,用生成器流式yield分块数据,并显式设置accept-ranges、content-length等头部。

怎样在python flask应用中实现断点续传的大文件下载?

Flask如何正确响应Range请求

断点续传依赖HTTP的Range头,客户端发起下载时会带上类似Range: bytes=1024-2047的请求,服务端必须返回206 Partial Content状态码,并设置Content-Range、Accept-Ranges等响应头。Flask默认不处理Range,需手动解析并构造响应。

关键点:不能直接用send_file()——它不支持分段;也不能用make_response()简单包装字节流——缺少头部校验和边界计算。

  • 先读取请求头:range_header = request.headers.get('Range'),为空则走完整下载流程(返回200)
  • 用正则提取范围:bytes=([0-9]+)-([0-9]*),注意末尾可能为空(如bytes=1000-表示“从1000到结尾”)
  • 文件总大小必须提前获取:os.path.getsize(filepath),用于校验范围合法性(比如start > filesize要返回416 Range Not Satisfiable)
  • Content-Range格式必须严格:bytes {start}-{end}/{filesize},其中end是含末位的偏移量(即end = min(end, filesize - 1))

用生成器流式返回文件片段

大文件不能一次性加载进内存,必须用生成器按块读取。但要注意:Flask的响应体若为生成器,需确保每个yield返回的是bytes而非str,且块大小建议设为8192或65536,太小导致系统调用频繁,太大占用内存。

常见错误是直接open(...).read()——这会把整个片段载入内存;或者用for line in f——文本模式会破坏二进制数据。

  • 务必以'rb'模式打开文件:with open(filepath, 'rb') as f:
  • 跳过起始位置:f.seek(start),然后循环f.read(chunk_size)直到读够length字节
  • 每次yield前检查是否已读完,避免多读(例如remaining 时改用<code>f.read(remaining))
  • 响应对象要显式设置content_type='application/octet-stream',否则浏览器可能误判为文本

为什么不能用send_from_directory实现断点续传

send_from_directory()虽方便,但它内部调用的是send_file(),而后者在收到Range头时**不会自动降级为206响应**,而是忽略该头、返回完整文件+200状态码。这意味着客户端收不到分段标识,下次断点请求会被当作新下载,覆盖已有部分。

python-script-generator
python-script-generator

快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。

下载

更隐蔽的问题是:某些Nginx或CDN配置下,send_from_directory()返回的响应可能被缓存层截断Content-Range头,导致客户端始终重头下载。

  • 实测中,即使手动加Response(headers={...})也无法覆盖send_from_directory()的内部逻辑
  • 替代方案只有自己构造Response对象,把生成器作为response参数传入
  • 若必须复用静态文件路由,可在反向代理层(如Nginx)启用slice模块,由其处理Range,Flask只负责提供原始文件路径

客户端请求头与服务端兼容性细节

不是所有客户端都发标准Range头。iOS Safari有时发Range: bytes=0-却不带If-Range,Android DownloadManager可能重复发相同范围,Chrome对Content-Range格式异常敏感(空格、大小写错一点就失败)。

服务端必须做容错:接受bytes=0-、bytes=-1000(倒序)、多个范围(虽然极少用),并统一转成单段处理。

  • 遇到bytes=-N时,start = filesize - N,end = filesize - 1
  • 忽略If-Range头(除非你实现了ETag校验逻辑),直接按Range返回
  • 响应中必须包含Accept-Ranges: bytes,否则部分旧版安卓下载器拒绝断点
  • 不要设置Cache-Control: no-cache——这会让浏览器放弃利用本地缓存继续下载,应设为public, max-age=3600配合ETag

最易被忽略的是文件锁和并发读取:同一文件被多个请求同时seek+read时,Python的file对象不保证线程安全,生产环境务必加threading.Lock或改用mmap(但mmap对超大文件有地址空间限制)。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1671

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4204

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1669

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

24377

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2987

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3007

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1163

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2323

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程