V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
工单节点使用指南
• 请用平和的语言准确描述你所遇到的问题
• 厂商的技术支持和你一样也是有喜怒哀乐的普通人类,尊重是相互的
• 如果是关于 V2EX 本身的问题反馈,请使用 反馈 节点
wty
V2EX  ›  全球工单系统

从阿里云 oss 下载文件,文件居然损坏了

  •  
  •   wty · 2020-09-14 01:36:28 +08:00 · 3047 次点击
    这是一个创建于 1538 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前测出用 axel 多线程(开了 4 线程)下载会出现这种情况,chrome 和 ossutil 下载的没问题

    对比了一下文件内容,出错的文件后面有部分变成从头开始下载的了,并且不止从头开始了一次。最终下载下来的文件大小相同。

    另外手机 app 里面看见的文件大小居然是错的,疑似单位换算用了 1000 除。网页版里的倒是对的。

    (感觉实在是太扯淡了,这 bug 有点多啊。。。)

    8 条回复    2020-09-14 20:39:29 +08:00
    wtks1
        1
    wtks1  
       2020-09-14 04:22:55 +08:00 via Android
    用 aria2 的多线程试试?目前已知 axel 在下载某些链接的时候无法追踪多次跳转的地址,不知道是不是这个问题导致的
    whileFalse
        2
    whileFalse  
       2020-09-14 07:27:02 +08:00
    手机 app 是什么 app
    wty
        3
    wty  
    OP
       2020-09-14 08:48:45 +08:00 via Android
    @whileFalse 就是叫 阿里云 的那个 app
    abo321
        4
    abo321  
       2020-09-14 13:38:52 +08:00
    您好。感谢您使用 OSS 和反馈。

    针对这个问题,我们本地使用 axel 工具做了测试,版本为 2.16.1,os 为 ubuntu 。分别通过 axel 和 curl 对下载的数据做 md5 对比,其值都是一样的。

    具体的测试如下,

    ===================

    测试命令 axel -n 4 -o axel-download-2.data http://skyranch-02.oss-cn-hangzhou.aliyuncs.com/curl.zip 4 个线程同时下载。

    抓包后,看到一共有 5 个 Get 请求
    (1) GET /curl.zip Range: bytes=1- 返回 Content-Length: 330978 , 报文的数据只返回了差不多 0x446C 数据
    (2) GET /curl.zip bytes=165489-248233 返回 Content-Length: 82745 ,
    (3) GET /curl.zip 返回 Content-Length: 330979 , 报文的数据只返回了差不多 0x2958c ( 169556 ) 数据, 涵盖 0- 165489 范围
    (4) GET /curl.zip bytes=248234-330978 返回 Content-Length: 82745
    (5) GET /curl.zip bytes=82744-165488 返回 Content-Length: 82745

    测试文件长度为 330979,330979/4 = 82744.75 ,分段为 82745, 分别通过 axel 和 curl 对下载的数据做 md5 对比,其值都是一样的。

    大概推出,这个工具的做法:
    (1) 请求为获取到 文件的 大小。通过 ranget 1- 模式获取 文件大小 比 head object 更具有通用性
    (2) - (5) 为 多线程请求,正好有 4 个并发 请求,最开始的请求 通过非 range 方式请求,读数据时,只读 需要的部分。其它并发按照 分片大小请求。

    ===================

    想和您确认下,您使用的 axel 工具是什么版本, 测试文件的大小,以及 用到的 axel 是不是 同一个?

    再次感谢您的反馈!
    wty
        5
    wty  
    OP
       2020-09-14 15:39:33 +08:00
    @abo321 您好,我用的是 Axel 2.17.9, wsl2 里的 ubuntu2004

    我也试了一下 2.16.1 版本,是正常工作的,抓包发现请求不太一样,

    16 版本第一个请求 range 是 1- ,17 版本是 0- (这点似乎没有影响),17 版本的每个下载请求都有 range 参数。

    问题出在下载最后一个 part 上,对一个 336700 字节的文件,16 版本的 range 是 252527-336699,17 版本 280583-336700 (估计是代码写错了),oss 对于这种请求处理是忽略 range 项,从头开始读,返回 http200 。

    但是根据 RFC2616 138 页的说法,服务器应该是把大小限制到文件大小,而不是从头开始读。以下是原文:

    If the last-byte-pos value is absent, or if the value is greater than
    or equal to the current length of the entity-body, last-byte-pos is
    taken to be equal to one less than the current length of the entity-
    body in bytes.

    另外上面还提到一个手机 app 单位换算错误的问题,也麻烦转达一下,谢谢!
    abo321
        6
    abo321  
       2020-09-14 19:22:21 +08:00
    @wty 谢谢您的回复。请问下您使用的 app 是 Android 版还是 IOS 版?
    abo321
        7
    abo321  
       2020-09-14 20:04:44 +08:00
    @wty 关于 Range Get 的问,可以参考下我们的官网文章《如何通过 HTTP Range 请求分段获取 OSS 资源》: https://help.aliyun.com/knowledge_detail/39571.html

    可以通过增加请求头 x-oss-range-behavior:standard 来兼容 RFC 定义的行为。

    =================
    兼容行为
    使用 HTTP Range 时,增加请求头 x-oss-range-behavior:standard,可以改变指定范围不在有效区间时 OSS 的行为。行为改变的示例如下。

    注:此处假设 Object 资源大小为 1000 字节,Range 有效区间为 0-999 。

    Range: bytes=500-2000:末字节超出有效区间,返回 500-999 字节范围内容。
    Range: bytes=1000-2000:首字节超出有效区间,返回错误 416 (InvalidRange)。
    Range: bytes=1000-:首字节超出有效区间,返回错误 416 (InvalidRange)。
    Range: bytes=-2000:指定范围超出有效区间,返回 0-999 字节,即完整的文件内容。
    =================

    有任何问题,都可以在阿里云存储官网( https://www.aliyun.com/product/oss )钉钉扫描二维码找到我们!

    再次感谢您的反馈!我们会始终认真倾听各种反馈,并持续不断的改进产品,为用户提供更好的云存储服务!
    wty
        8
    wty  
    OP
       2020-09-14 20:39:29 +08:00 via Android
    @abo321 Android 版
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2926 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:49 · PVG 10:49 · LAX 18:49 · JFK 21:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.