Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复下载文件时Accept-Ranges为none时会无限重复请求该文件的问题 #56

Conversation

fzls
Copy link
Contributor

@fzls fzls commented Apr 16, 2021

问题描述

在下载特定文件时,返回的headers中Accept-Ranges值为none,而不是bytes,这种情况下无法通过流式接口来下载文件

解决方案

在检测到headers中Content-Length时,先判读下此时的Accept-Ranges是否为none,若是,则不走流式下载流程,改为直接将本次请求返回的content写入文件中

重现流程

可使用下列两个文件进行对比测试,其中第一个文件使用修改前版本将在尝试重新请求url来获取content_length的地方无限循环。

Accept-Ranges: none
https://dev34.baidupan.com/041701bb/2021/04/17/13c23e0da782fb78473c864e3b514e10.txt?st=rvpH9vZqSkeDIwpVEUddiQ&e=1618595533&b=ByABcglsB3AAClFqAD9SOFNyCz8MYQp1AAwNcAZgXyQGCw9mBWtTMAQ_bVCxXcwV5VXQ_c&fi=42372783&pid=113-106-106-98&up=2

Accept-Ranges: bytes
https://dev76.baidupan.com/041701bb/2021/04/17/4e04444aee213d4bcb4c0b17ed50f1ed.txt?st=rUbmhkeeriEPi5cw9bFUwg&e=1618596692&b=AzMOe1ApA1lXY1R3BSEDaAUPXndUJQpoATNaIwFjXi4HCgt_bBHcCYgQjUXRQLlAgVHlZcQ_c_c&fi=42372737&pid=113-106-106-98&up=2

示例截图

none
bytes

参考文献

https://tools.ietf.org/html/rfc7233#section-2.3

@zaxtyson
Copy link
Owner

文件比较大的时候,会不会出现 Accept-Rangesnone 的情况呢?如果可能的话,就不能一次性读取 resp.content 再写入文件,requests 的请求方法是阻塞式的,会等待 content 全部读取到内存。读取较大的文件就会阻塞很长时间,这个过程中不会去调用下载回调函数显示进度,看起来就像卡死了一样。

考虑到一部分用户会解除官方限制,这个文件名可能是程序伪装出来的,下载完成仍然需要尝试反序列化文件尾部数据去得到真实文件名。更糟糕的是,如果不能使用 Range 请求,断点续传的功能就要受影响,而且我们无法得知下载进度,同时大文件分段合并功能也会受到影响(如果当前文件是某一个大文件的数据块)。

所以,我们先得确定 Accept-Ranges: none 的具体出现场景,如果只在 txt 文件上出现,那就比较好解决。

@fzls
Copy link
Contributor Author

fzls commented Apr 25, 2021

文件比较大的时候,会不会出现 Accept-Rangesnone 的情况呢?如果可能的话,就不能一次性读取 resp.content 再写入文件,requests 的请求方法是阻塞式的,会等待 content 全部读取到内存。读取较大的文件就会阻塞很长时间,这个过程中不会去调用下载回调函数显示进度,看起来就像卡死了一样。

考虑到一部分用户会解除官方限制,这个文件名可能是程序伪装出来的,下载完成仍然需要尝试反序列化文件尾部数据去得到真实文件名。更糟糕的是,如果不能使用 Range 请求,断点续传的功能就要受影响,而且我们无法得知下载进度,同时大文件分段合并功能也会受到影响(如果当前文件是某一个大文件的数据块)。

所以,我们先得确定 Accept-Ranges: none 的具体出现场景,如果只在 txt 文件上出现,那就比较好解决。

-。-目前我就遇到那一种情况,暂时不知道其他情况哈哈。前几天调试的时候,我记得还遇到一次Accept-Ranges为bytes,但是没有Content-Length header的情况

@zaxtyson
Copy link
Owner

目前只有 txt 文件会出现没有 Content-Length 的情况,只要分享链接被人下载一次,就会出现 Content-Length

@fzls
Copy link
Contributor Author

fzls commented Apr 25, 2021

目前只有 txt 文件会出现没有 Content-Length 的情况,只要分享链接被人下载一次,就会出现 Content-Length

原来是这样-。-那天遇到这个懵逼了好一会

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

我发现文件上传之后, 第一次下载 Accept-Ranges 都是 None, 各种类型的文件都是这样, 但是仍然可以使用 Range Request, 断点续传没有问题. 第二次下载才会出现 'Accept-Ranges': 'bytes, bytes'

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

我发现文件上传之后, 第一次下载 Accept-Ranges 都是 None, 各种类型的文件都是这样, 但是仍然可以使用 Range Request, 断点续传没有问题. 第二次下载才会出现 'Accept-Ranges': 'bytes, bytes'

-.-我之前测试的时候好像不可以,不知道是不是哪里处理的不一样

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

现在没办法复现无限请求的情况🙈

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

现在没办法复现无限请求的情况🙈

orz,那我先用本地修改版本吧哈哈,暂时用起来也没啥问题

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

要不获取content_length的地方的地方加一个循环次数判定,比如超过10次还没请求成功,这时候就判定是出现了无限请求的状况,这时候就用我这个方案处理-。-

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

我早上拿去改了一下, 没有 Accept-Ranges 时也是一次读取一个 chunk , 进度回调的 total_size 改成 float("inf"), 进度条只显示已经下载的大小, 数据不再以追加的方式写入文件, 下载完成也会去处理文件尾部的隐藏信息.

但是发现目前文件第一次下载 Accept-Ranges 都是 none, 但其实是可以支持 Range 请求的. 如果真的不支持就麻烦些了, 我们绕过官方限制的时候数据是分块上传的, 为了避免重复写磁盘, 下载是直接追加到一个文件里面的. 如果某一块文件没法断点续传, 就要把上一次下载未完成的数据块截掉,重新追加.

Content-Length 一般是 txt 文件第一次下载没有, 读取一个字节再去请求一次就解决了, 我之前的逻辑是没有拿到就去读 1 byte 数据, 因为都是第二次请求就能拿到, 所以这里没加加一个计数器, 而是写了了死循环, 这里的确应该有限次请求, 否则服务器一直不给 content-length 就会把文件一字节一字节读完才停

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

我早上拿去改了一下, 没有 Accept-Ranges 时也是一次读取一个 chunk , 进度回调的 total_size 改成 float("inf"), 进度条只显示已经下载的大小, 数据不再以追加的方式写入文件, 下载完成也会去处理文件尾部的隐藏信息.

但是发现目前文件第一次下载 Accept-Ranges 都是 none, 但其实是可以支持 Range 请求的. 如果真的不支持就麻烦些了, 我们绕过官方限制的时候数据是分块上传的, 为了避免重复写磁盘, 下载是直接追加到一个文件里面的. 如果某一块文件没法断点续传, 就要把上一次下载未完成的数据块截掉,重新追加.

Content-Length 一般是 txt 文件第一次下载没有, 读取一个字节再去请求一次就解决了, 我之前的逻辑是没有拿到就去读 1 byte 数据, 因为都是第二次请求就能拿到, 所以这里没加加一个计数器, 而是写了了死循环, 这里的确应该有限次请求, 否则服务器一直不给 content-length 就会把文件一字节一字节读完才停

哈哈哈能解决卡在那的问题就行

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

你是卡在重复获取 content-length 吗, Accept-Ranges 似乎没有造成影响

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

你是卡在重复获取 content-length 吗, Accept-Ranges 似乎没有造成影响

-.-我之前是对比了会卡住和不会卡住的两个文件,看请求结果差异只有这个Accept-Ranges-。-

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

我这边文件第一次下载 Accept-Ranges 必然是 none, 就会跳到你那段逻辑, 会阻塞到文件全部读入内存才写入磁盘

image

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

我这边文件第一次下载 Accept-Ranges 必然是 none, 就会跳到你那段逻辑, 会阻塞到文件全部读入内存才写入磁盘

image

=、=你看看咋改比较好,这块我也不熟,之前是调试的时候对比看哪里可能有问题来针对性调整的

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

之前的直链已经失效了, 能分享一下那个奇怪的文件吗

@fzls
Copy link
Contributor Author

fzls commented May 9, 2021

之前的直链已经失效了, 能分享一下那个奇怪的文件吗

=.=太久了,找不到那个文件了,尴尬-。-刚重试了下,新的文件好像没出现这个。。。。

@zaxtyson
Copy link
Owner

zaxtyson commented May 9, 2021

所以说很迷, 无法复现就无法解决问题

Copy link
Owner

@zaxtyson zaxtyson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed #58 , #56 暂未复现

@zaxtyson zaxtyson merged commit 99facc2 into zaxtyson:master May 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants