《拿下奇怪的前端报错》:1比特丢失导致的音视频播放时长无限增长-浅析http分片传输核心和一个坑点

问题背景

在一个使用MongoDB GridFS实现文件存储和分片读取的项目中,同事遇到了一个令人困惑的问题:音频文件总是丢失最后几秒,视频文件也出现类似情况。更奇怪的是,播放器显示的总时长为无限大。这个问题困扰了团队成员几天,都没有解决,因为架构这块我负责的,最后当然就需要我来深入调查了(本来是想蒙混过去的,毕竟影响其实不大,但因为刚好有点空闲)。

  • 在应用中,音频时长为无限,可以不停的快进也就是时长无限增长,大部分手机都如此,除了一部分手机正常
  • 在浏览器中单独打开音频文件,播放正常
  • 文件使用Mongodb的GridFS存储在数据库,通过http接口对外提供读取接口

HTTP分片传输简介

在深入问题之前,让我们先了解一下HTTP分片传输的基本概念,这对理解后续的调试过程至关重要。这部分内容很久之前看网络相关文档的时候,有初略的了解,大概就是前端请求时,后端支持分片可返回部分数据+总数据长度,然后前端就可以按需读取了。

HTTP分片传输(HTTP Range Requests)允许客户端请求资源的部分内容,而不是整个资源。这在处理大文件,特别是音频和视频流时非常有用。主要涉及以下HTTP头:

  1. Range:客户端在请求中使用此头来指定所需的字节范围。
    例如:Range: bytes=500-999表示请求从第500字节到第999字节的内容。

  2. Content-Range:服务器在响应中使用此头来指明实际返回的字节范围。
    例如:Content-Range: bytes 500-999/1234表示返回的是500-999字节,总文件大小为1234字节。

  3. Accept-Ranges:服务器使用此头来告诉客户端它支持范围请求。

重要的是,HTTP规范中定义的Range是包含性的(inclusive),这意味着Range: bytes=0-499实际上请求了500个字节。这里是一个非常容易出错的点,因为在大多数的编程语言中,对类似数组数据的操作,结尾位置的数据都是不包含的,这也是一个坑点,刚入行不久的小伙伴很可能就跳进去了,毕竟随能够记得那么细呢?而且是一个反常见模式的知识点!

调试过程

1. 初步分析

首先,我注意到播放器的duration显示为无穷大。为了进一步测试,我尝试将currentTime设置为一个非常大的值,但问题依然存在。但是在单独的页面播放和oppo的某手机播放没问题,就猜测是某个特殊点的兼容性问题,但部分尝试做了兼容,所以正常,但大部分的设备或者webview都没有兼容,导致这个问题没被处理,从而出现时长无限。这时候测试得到一个比较重要的信息:

  • 特别小的文件,时长在5秒内的不会出现无限时长,视频文件大概率都会出现

于是就进一步猜测,肯定和网络传输有关,而且和文件体积有关系,这时候想起了大文件分片,因为上传的时候就是分片上传的

2. 网络请求分析

观察到网络请求一直处于pending状态,我怀疑可能是由于socket没有正确关闭导致无限加载。我尝试在数据流关闭后结束请求,但这并没有解决问题。

  1. 而且发现浏览器在不同的发送包内容基本一样的请求

3. 请求头分析

仔细查看请求头,我发现了一些奇怪的Range请求,如Range=11333-11333/11334。起初,我认为可能是因为起始值和结束值相同导致的问题。我尝试在这种情况下重写Range,对于Range=11333-这样的请求则返回416状态码。但这些措施都没有解决问题。

也就是这里引起了我的警觉,因为是不停的在请求,一开始的时候,还以为是触发了某个浏览器的bug,但是分析请求头,有一点引起可我的注意,就是11333-11333/11334 ,为什么会请求这样的数据,第一反应是一个0字节的请求

然后我就开始读HTTP1.1-rfc2616规范文档,发现这了这个反直觉的坑,那就是范围的结尾值是包含的。

这里基本上我猜测到了问题出现的原因,下一步就是验证了

附rfc的说明 - inclusive,开始还不确定这个单词的意思
在这里插入图片描述

4. 深入源码

分析第三方库的源码后,我发现了问题的根源:

  • HTTP的Content-Range头中,start和end都是包含的(inclusive)。
  • 而在JavaScript和MongoDB中,类似slice()这样的操作,end是不包含的(exclusive)。

这种不一致性导致了在处理最后一个字节时出现问题。具体来说:

  1. 当客户端请求最后一个字节时(例如Range: bytes=11333-11333),服务器正确地解释了这个请求。
  2. 但是,当服务器使用JavaScript或MongoDB的API来获取这个范围的数据时,由于end是exclusive的,实际上没有返回任何数据。
  3. 这导致客户端认为还有更多数据需要获取,因此会继续发送请求,造成无限加载的情况。

解决方案

为了解决这个问题,便对getDownloadStream方法进行了修改-重写,类似于下面的方式-先缓存老方法,再修改请求参数,再调用老方法:

const oldFun = obj.a;
obj.a = function(a1, a2) {if (a2.end) {a2.end += 1;}return oldFun(a1, a2);
}

这个简单的修改确保了JavaScript/MongoDB的操作范围与HTTP请求的Range一致,解决了缺少最后一个字节的问题。通过将end值增加1,确保了包含了请求范围的最后一个字节。

经验总结

  1. HTTP协议的深入理解很重要:尤其是请求头参数的精确含义,对于解决复杂问题至关重要。在这个案例中,理解Range请求的包含性本质是解决问题的关键。

  2. 框架设计的重要性:这次调试过程让我意识到了Koa等框架设计的优势。能够在一个中间件中同时处理请求和响应,大大方便了调试过程。

  3. 细节决定成败:在这个案例中,仅仅一个字节的差异就导致了严重的用户体验问题。这提醒我们在处理底层数据时必须格外小心,特别是在处理不同系统间的数据交换时。

  4. 开源贡献的价值:通过这次经历,我不仅解决了自己的问题,还有机会通过PR为开源社区做出贡献,提升了项目的整体质量。这展示了开源社区如何通过集体智慧来解决复杂问题。

  5. 跨系统集成的挑战:这个问题突出了在集成不同系统(如HTTP服务器、JavaScript运行时和MongoDB)时可能遇到的细微差异。在设计跨系统解决方案时,需要特别注意这些潜在的不一致性。

结语

这个看似简单的问题背后隐藏着HTTP协议、JavaScript特性和数据库操作之间的微妙差异。通过耐心的调试和深入的分析,我不仅解决了问题,还加深了对各种技术细节的理解。这再次证明,在软件开发中,“魔鬼藏在细节里”。

对于其他可能遇到类似问题的开发者,建议深入理解所使用的每个组件的特性,特别是在处理底层数据传输时。同时,这个案例也强调了全面测试的重要性,尤其是在处理边界情况时。通过分享这种经验,可以共同提高整个开发社区的技术水平和问题解决能力。

本文主要是复盘之前工作中遇到的一个奇怪的前端问题,并且是我个人的第一次开源代码贡献,还提交了两次,第一次因为格式不对没写注释-个人仓库管理员没接受,第二次说明了情况并详细说明和备注了解释等才通过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/55532.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java项目-基于Springboot的应急救援物资管理系统项目(源码+说明).zip

作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…

工业自动化为什么依赖光耦隔离器 --- 腾恩科技

光耦合器隔离器在工业自动化中必不可少,可确保信号传输,同时保护敏感电子设备和人员免受高压影响。选择合适的光耦合器隔离器取决于对操作环境和隔离要求的了解。本文将重点介绍在为工业应用选择光耦合器隔离器时需要考虑的关键因素。 光耦合器隔离器在工…

上传图片到github上,生成链接在Typora中使用(解决Typora的md文件在分享时的丢失问题)

上传图片到github上,生成链接在Typora中使用(解决Typora的md文件在分享时的丢失问题) 在GitHub上从操作 创建一个 GitHub 仓库: 登录 GitHub,创建一个新的仓库来存储图片。 生成 GitHub 令牌: 在 GitHub 中,前往“Settings” > “Developer settings” > “Pers…

AUTOSAR_EXP_ARAComAPI的5章笔记(12)

☞返回总目录 5.4.6 方法 骨架侧的服务方法是抽象方法,必须由继承骨架的服务实现子类进行重写。让我们来看一下我们服务示例中的 Adjust 方法: /*** 对于所有输出和非空返回参数* 生成一个包含非空返回值和/或输出参数的封装结构。*/ struct AdjustOu…

UE4 材质学习笔记08(雨滴流淌着色器/雨水涟漪着色器)

一.雨滴流淌着色器 法线贴图在红色通道和绿色通道上,那是法线的X轴和Y轴,在蓝色通道中 我有个用于雨滴流淌的蒙版,在Alpha通道中,有个时间偏移蒙版。这些贴图都是可以在PS上制作做来的,雨滴流淌图可以直接用笔刷画出来…

永恒之蓝漏洞

MS17-010是微软于2017年3月发布的一个安全补丁,旨在修复Windows操作系统中的一个严重漏洞,该漏洞被称为“永恒之蓝”(EternalBlue)。这个漏洞影响了Windows的Server Message Block(SMB)协议,允许…

Java集合剖析3】ArrayList

目录 拓展 1. 在面试时如何讲解一个集合的底层? 2. IDEA如何查看底层源码? 一、ArrayList底层数据结构 二、插入方法的具体实现 三、ArrayList底层原理总结 拓展 1. 在面试时如何讲解一个集合的底层? 底层的数据结构。插入方法的具体实现。…

vue综合指南(六)

​🌈个人主页:前端青山 🔥系列专栏:Vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:vue综合指南 目录 101、Vue 框架怎么实现对象和数组的监听? 102、Proxy 与 Object.d…

10 分钟使用豆包 MarsCode 帮我搭建一套后台管理系统

以下是「 豆包MarsCode 体验官」优秀文章,作者把梦想揉碎。 十分钟使用豆包 MarsCode 搭建后台管理项目 在这个快节奏的时代,开发者们总是希望能够快速、高效地完成项目的搭建与开发工作。无论是初创企业还是大型公司,后台管理系统都是必不可…

SpringBoot1~~~

目录 快速入门 依赖管理和自动配置 修改自动仲裁/默认版本号 starter场景启动器 自动配置 修改默认扫描包结构 修改默认配置 读取application.properties文件 按需加载原则 容器功能 Configuration Import ​编辑 Conditional ImportResource 配置绑定Configur…

要在 Git Bash 中使用 `tree` 命令,下载并手动安装 `tree`。

0、git bash 安装 git(安装,常用命令,分支操作,gitee,IDEA集成git,IDEA集成gitee,IDEA集成github,远程仓库操作) 1、下载并手动安装 tree 下载 tree.exe 从 tree for Windows 官方站点 下载 tree 的 Windows 可执行文件。tree for Window:https://gnuwin32.source…

鸿蒙应用开发:全面认识鸿蒙系统

前言 随着智能设备的普及和物联网的发展,对操作系统的需求也越来越多样化。鸿蒙操作系统作为一款面向全场景的分布式操作系统,其适用范围非常广泛,从智能手机到家用电器,再到工业设备,都能找到应用场景。特别是在智能…

Nginx如何配置Gzip

Nginx 配置 Gzip 压缩可以显著减小传输的文件大小,提高网页加载速度。以下是在 Nginx 中配置 Gzip 的详细步骤: 一、找到 Nginx 配置文件 Nginx 的配置文件通常位于 /etc/nginx/nginx.conf 或 /usr/local/nginx/conf/nginx.conf(取决于 Ngin…

鸿蒙网络编程系列22-Web组件文件上传示例

1. web组件文件上传功能简介 鸿蒙的web组件可以加载网页,如果网页本身具备文件上传功能的话就比较尴尬了,因为html上传文件时,允许用户选择本地文件,但是鸿蒙因为安全性的考虑,只允许操作沙箱中的文件,所以…

物联网的应用以及优势

物联网智能项目涵盖了多个行业领域,随着技术的不断进步和普及,越来越多的应用案例成为主流趋势。此篇文章将概述一些主要的物联网智能项目类别及其优势和日常使用场景: 主流物联网智能项目 1. 智能家居: •优势: 提升居住体验,…

双十一母婴有什么好物推荐?双十一这五款母婴好物不容错过!

随着双十一购物狂欢节的来临,母婴用品市场再次迎来了消费者的热切关注。作为家长们为孩子和自身挑选必需品的重要时刻,母婴用品的质量和安全性无疑成为了关注的焦点。在众多品牌和商品中,我们精心筛选了本年度最受欢迎的母婴用品,…

24/10/14 算法笔记 循环神经网络RNN

RNN: 一种专门用于处理序列数据的神经网络,它能够捕捉时间序列中的动态特征。RNN的核心特点是其循环连接,这允许网络在不同时间步之间传递信息,从而实现对序列数据的记忆和处理能力。 应用的场景: 自然语言处理(NLP&…

关于Python AI 编程助手Fitten Code的应用体验以及Python 修改删除 sys.path 路径以实现两个项目代码的合并

一、关于Python AI 编程助手Fitten Code的应用体验 AI现在无孔不入,现在都开始进入到编程中了,有一个能适用多种编译器环境的AI编程插件 Fitten Code。其适配了 Viusal Studio,VS Code(本文使用),JetBrains 系列(本文使用)以及Vim…

如何使用C#实现Padim算法的训练和推理

目录 说明 项目背景 算法实现 预处理模块——图像预处理 主要模块——训练:Resnet层信息提取 主要模块——信息处理,计算Anomaly Map 主要模块——评估 主要模块——评估:门限值的确定 主要模块——推理 写在最后 项目下载链接 说…

进入 Searing-66 火焰星球:第一周游戏指南

Alpha 第四季已开启,穿越火焰星球 Searing-66,带你开启火热征程。准备好勇闯炙热的沙漠,那里有无情的高温和无情的挑战在等待着你。从高风险的烹饪对决到炙热的冒险,Searing-66 将把你的耐力推向极限。带上充足的水,天…