从断点续传故障排查,分析浏览器是怎么实现断点下载的

自研实现文件上传下载的中间件在测试阶段发现断点续传有问题。具体表现是:使用wget下载mp4文件可以正常播放,用google浏览器打开链接,google浏览器无法正常播放mp4视频。

排查思路首先是打开浏览器的开发者工具视图,查看网络请求。发现浏览器一共发起两个请求,一个是不带Range的下载整个文件的请求,一个是带Range: bytes=0-的http range请求,这两个请求都是响应2xx状态码。

请求状态码正常,那么只能抓包分析了。

通过tcpdump命令抓取这两个请求的数据包,然后用Wireshark工具分析。

不带Range的下载整个文件的请求,抓包结果如下:

其中36780端口是中间件服务的端口。从截图可以看出,是浏览器主动向服务端发起的断开连接,TCP报头标志位为RST。然后也能看出基本每个TCP数据包都重传了两次,客户端也重复ACK了两次,说明也没有丢包。

那为什么数据还没有传完,也没有什么异常,浏览器为什么要主动断开连接呢?

接着我们看带Range: bytes=0-的http range请求,抓包结果如下:

基本跟前一个请求的表现一致,也是浏览器主动断开了连接,数据也没有传完。

我打算换个浏览器看看,然后我换成使用Safari浏览器。同样的,视频也无法在Safari浏览器上播放。

查看Safari浏览器的网络请求,同样也是发起了两次请求,一次是下载完整文件的请求,一次是http range请求。下载完整的文件请求,响应状态码是200,但为什么显示红色异常?而google浏览器是显示正常。

通过抓包分析后,其实与google浏览器的表现是一样的,也是浏览器主动断开的连接。

浏览器为什么会发起两个请求?感谢这篇文章:www.hustyx.com/misc/358/

我觉得这篇文章有些地方说的不对,因为从表现看对不上,下面是我个人理解的浏览器播放mp4视频的流程:

Google浏览器:

  1. 浏览器不知道服务端是否支持range请求,所以它会发送一个普通的http请求以获取整个视频文件。
  2. 浏览器发送一个range探测请求Range: bytes=0-,服务端接收后会补齐终点位置,返回的是: Content-Range: bytes 0-end/total,这样浏览器就拿到了总文件大小。浏览器不会等到接收完数据,不管响应的数据有没有接收完,他会立马断开连接,前一步下载整个文件请求的连接也会断开。
  3. 如果探测请求探测到服务端支持range协议,那么浏览器就开始走Range协议。Google浏览器总是发送 Range: bytes=start- (不指定end),start为上次接收到的位置,服务端每次都补齐end和total,返回状态码206,表示Partial Content,浏览器开始同步播放视频。循环反复直到文件下载完。

Safari浏览器:

  1. 浏览器不知道服务端是否支持range请求,所以它会发送一个普通的http请求以获取整个视频文件。
  2. 浏览器发送一个range探测请求Range: bytes=0-1,服务端接收后会补齐终点位置,返回的是: Content-Range: bytes 0-end/total,这样浏览器就拿到了总文件大小。如果探测请求探测到服务端支持range协议,前一步下载整个文件请求的连接也会立即断开。
  3. 如果探测请求探测到服务端支持range协议,那么浏览器就开始走Range协议。接着浏览器发送Range: bytes=0-end,浏览器不会等到接收完数据,接收一部分数据后他会立马断开连接。
  4. Safari浏览器总是发送Range: bytes=start-end,start接着前一次接收到的end位置开始(每一次取多少字节看不出规律)。循环反复直到文件下载完。

到这就真相了,由于浏览器的探测请求不会等待所有数据响应完成,如果探测到服务端支持range协议,那么就会断开下个整个文件的请求的连接。

现在再来分析异常,我们从Safari浏览器的第二个请求发现了问题所在。

从截图可以看出,浏览器请求的range是0-1,而服务端响应的是0-13250517/13250517,而且end还错了,应该是文件大小减1。所以服务端处理分片下载的逻辑,响应头Content-Range是有问题的。

修复后视频就能正常播放了。

相关推荐
小蒜学长几秒前
基于Python的微博热搜话题可视化分析系统的设计与实现(代码+数据库+LW)
后端·python·django·数据可视化·情感分析·微博热搜
BingoGo3 分钟前
Whim 是什么?一门把 PHP 被否决的设想真跑起来的实验语言
后端·php
IT_陈寒22 分钟前
Java序列化坑了我三天,原来问题出在这个默认方法
前端·人工智能·后端
一条泥憨鱼25 分钟前
苍穹外卖【day10| 来电提醒和客户催单】
java·后端·websocket·苍穹外卖
ly768935 分钟前
Spring Boot 3.2 虚拟线程在 Web 层与 JDBC 池的实践边界
前端·spring boot·后端·tomcat·jdbc·虚拟线程
盖伦发发1 小时前
SpringCloud Alibaba Sentinel 教学:限流、熔断、降级、线程/信号量隔离、活动过载保护
后端·软件工程
考虑考虑9 小时前
数据库中的EXISTS
运维·数据库·后端
郑州光合科技余经理10 小时前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
毅炼10 小时前
Rover-Suite 开源发布:轻量服务注册中心与网关一体化方案
java·后端·系统架构·gateway
苏三说技术14 小时前
为什么越来越多人用OpenWiki?
后端