Safari中无法播放视频,“Failed to load resource: 插件处理的载入” 或 “尝试载入资源时发生错误。”

广告位招租
扫码页面底部二维码联系

今天遇到一个诡异的情况,在chrome中【转载请注明来源】【版权所有】唐霜 www.tangshuang.net好好的视频播放,到了safari中却看到【作者:唐霜】著作权归作者所有,禁止商业用途转载。一个毁坏的视频图标:

未经授权,禁止复制转载。【本文首发于唐霜的博客】

【原创不易,请尊重版权】转载请注明出处:www.tangshua转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】ng.net

打开元素检查,发现红色提示“Failed本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。 to load resource: 插本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。件处理的载入”,新窗口打开视频链接,在网【未经授权禁止转载】转载请注明出处:www.tangshuang.net络中看到视频请求红色,点击看到“尝试载入【作者:唐霜】【未经授权禁止转载】资源时发生错误。”。

原创内容,盗版必究。本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。【本文受版权保护】

经过一番排查,了解到出现该问题的原因是

著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。

当播放视频时,浏览器通常不会一次性下载整【本文受版权保护】【作者:唐霜】个视频文件,而是会发送 范围请求(Range Requests),分块下【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。载视频。这使得用户可以快速开始播放、拖动本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net进度条,并节省带宽。Safari 对此要【本文受版权保护】【本文首发于唐霜的博客】求尤其严格。如果你的服务器(比如 Ngi著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshuang.netnx, Apache, Node.js 【原创不易,请尊重版权】【本文首发于唐霜的博客】等)没有正确配置来响应这些请求,Safa未经授权,禁止复制转载。【转载请注明来源】ri 就会报错。

【未经授权禁止转载】未经授权,禁止复制转载。【版权所有】唐霜 www.tangshu本文作者:唐霜,转载请注明出处。【作者:唐霜】ang.net
本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.n本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。et 获取更多精彩内容】【原创内容,转载请注明出处】

国内的大模型对此一无所知,还是googl【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.nete gemini如一位经验丰富的老手,最本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。快找到问题。虽然一开始我也不确定是否是因【关注微信公众号:wwwtangshuangnet】【原创内容,转载请注明出处】为这个原因,但是后面处理后验证了这个说法【版权所有,侵权必究】未经授权,禁止复制转载。

本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshu【版权所有,侵权必究】【转载请注明来源】ang.net

我开始着手按照这个思路进行调整。

转载请注明出处:www.tangshua著作权归作者所有,禁止商业用途转载。【作者:唐霜】ng.net【本文受版权保护】【版权所有】唐霜 www.tangshu【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。ang.net

我观察了自己服务端返回资源的逻辑,特别是转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。视频资源,如果服务器上存在对应的视频文件原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net,我会以流式返回资源,具体即在heade本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。rs中增加:

【本文首发于唐霜的博客】本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshua【未经授权禁止转载】转载请注明出处:www.tangshuang.netng.net
Connection: keep-alive
Transfer-Encoding: chunked
这样就可以利用浏览器的特性,分片加载资源【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。
本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。
然而在视频播放场景下,safari则严格著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】要求range requests,这就会转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。带来问题。range requests会【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。在请求时带上range头:
著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】原创内容,盗版必究。
Range: bytes=500-999
意思是浏览器发出请求,要求服务端返回资源【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。的500-999个比特。
【本文首发于唐霜的博客】【作者:唐霜】【访问 www.tangshuang.n本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】et 获取更多精彩内容】
此时,服务端应该返回:
原创内容,盗版必究。【作者:唐霜】
HTTP/1.1 206 Partial Content
Content-Range: bytes 500-999/2000
Content-Length: 500
Content-Type: video/mp4

这是非常标准的响应,即服务端同意返回第5本文版权归作者所有,未经授权不得转载。【转载请注明来源】00-999个比特。在这个响应中Cont【原创不易,请尊重版权】【本文首发于唐霜的博客】ent-Length是必须的,而且值为r【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。ange比特数。206状态码表示这是一个本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。未完成的资源响应,客户端应该继续请求,直【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】到拿到最终结果。

著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】【版权所有】唐霜 www.tangshu【访问 www.tangshuang.net 获取更多精彩内容】【未经授权禁止转载】ang.net【作者:唐霜】

但是,如果按照上面的响应方式,我需要在服【访问 www.tangshuang.net 获取更多精彩内容】【作者:唐霜】务端做大改造,即我需要按比特截取视频,这【本文受版权保护】【未经授权禁止转载】显然有点强人所难。因此,我探索是否可以有原创内容,盗版必究。【本文受版权保护】其他方式,在改动比较小的情况下解决。

原创内容,盗版必究。本文作者:唐霜,转载请注明出处。【本文受版权保护】【版权所有,侵权必究】

最后,我找到一种方案,在原来响应200状原创内容,盗版必究。【本文首发于唐霜的博客】态码的情况下,我返回:

【关注微信公众号:wwwtangshua【版权所有】唐霜 www.tangshuang.net【本文受版权保护】ngnet】【本文受版权保护】原创内容,盗版必究。
Accept-Ranges: bytes
Content-Length: 552302

即我返回了整个视频的长度,并添加了Acc【未经授权禁止转载】【原创内容,转载请注明出处】ept-Ranges头来标识。

【作者:唐霜】【转载请注明来源】

完成这个调整之后,我发现直接请求视频地址转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。,会报502,看nginx日志后发现是T【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】ransfer-Encoding: ch【原创内容,转载请注明出处】【原创不易,请尊重版权】unked与Content-Length【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】两个头互斥引起的。经过调整,在Range本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net Requests的场景下,不在使用Tr【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。ansfer-Encoding: chu著作权归作者所有,禁止商业用途转载。【转载请注明来源】nked进行响应。

本文版权归作者所有,未经授权不得转载。【本文受版权保护】【访问 www.tangshuang.n【本文首发于唐霜的博客】【未经授权禁止转载】et 获取更多精彩内容】未经授权,禁止复制转载。

最终通过这样的改造,safari可以正常响应播放视频了。本来以为解决了,但是没想到发现其实是有问【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。题的,当视频体积稍大的时候,报错依然存在【本文受版权保护】本文作者:唐霜,转载请注明出处。。safari实际上还是以range模式【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】拉取视频数据,因此,还是必须实现rang【未经授权禁止转载】原创内容,盗版必究。e请求改造。

未经授权,禁止复制转载。未经授权,禁止复制转载。【版权所有,侵权必究】原创内容,盗版必究。

标准的Range响应要使用206状态码。【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。因此,世纪改造还是比较复杂的,下面是大致本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】的代码:

【关注微信公众号:wwwtangshua【未经授权禁止转载】原创内容,盗版必究。ngnet】转载请注明出处:www.tangshua【本文受版权保护】转载请注明出处:www.tangshuang.netng.net转载请注明出处:www.tangshua【原创不易,请尊重版权】【版权所有,侵权必究】ng.net本文版权归作者所有,未经授权不得转载。
const responseBuffer = (buff) => {
        const range = header('range');
        const byteLength = buff.byteLength;

        // 当不存在range请求头时,直接返回
        if (!range) {
            header('Content-Length', byteLength);
            return buff;
        }

        const [start, end] = range.replace('bytes=', '').split('-');

        // 当range头为 Range: bytes=0- 时,表示读取整个视频,因此也直接返回
        if (start === '0' && end === '') {
            header('Content-Length', byteLength);
            return buff;
        }

        const begin = start === '' ? 0 : +start;
        const to = end === '' ? byteLength : +end + 1;

        header('accept-ranges', 'bytes');

        // 处理一些不符合请求要求的情况
        if (Number.isNaN(begin) || Number.isNaN(to) || begin < 0 || to > byteLength || begin >= to) {
            status(416);
            header('Content-Range', `bytes */${byteLength}`);
            return;
        }

        const length = to - begin;
        header('Content-Length', length);
        header('Content-Range', `bytes ${start}-${end}/${byteLength}`);
        // 当返回Content-Range时,状态码必须为206
        status(206);

        const clip = buff.slice(begin, to);
        return clip;
    };

通过上面这段代码,当浏览器发起的请求为不【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。同情况时,返回不同的请求头和buff,这未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net样就可以让safari正常播放。

本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshua转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】ng.net【作者:唐霜】

此外,还有一个点需要注意,safari视本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】频请求其实分了两个阶段:

著作权归作者所有,禁止商业用途转载。【作者:唐霜】【关注微信公众号:wwwtangshua【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】ngnet】【版权所有,侵权必究】

未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。

第一阶段是与视频建立可读性连接,并根据c【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】ontent-length,计算rang【版权所有,侵权必究】【本文受版权保护】e bytes的大小,确认视频可读性之后【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。,这个连接被放弃,之后开始加载video【原创不易,请尊重版权】【作者:唐霜】标签,上面的data:image/png【本文首发于唐霜的博客】【本文受版权保护】..就是video标签视频播放器的素材(未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】例如播放按钮、画中画图标等),在完成vi【作者:唐霜】【原创不易,请尊重版权】deo标签组件的渲染之后,才会发起第二阶【关注微信公众号:wwwtangshuangnet】【访问 www.tangshuang.net 获取更多精彩内容】段的连接。

【访问 www.tangshuang.n转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.netet 获取更多精彩内容】【关注微信公众号:wwwtangshua本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。ngnet】

在第一次连接时,请求并不带Ranges头原创内容,盗版必究。【转载请注明来源】,而是一个普通的http请求,在第二阶段未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net连接时才会带上Ranges头。第二阶段实本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。际上会发起多个range请求,上面截图中【未经授权禁止转载】未经授权,禁止复制转载。只有一个请求,是因为视频体积比较小,而当【转载请注明来源】著作权归作者所有,禁止商业用途转载。content-length较大时,sa【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。fari会自动拆分为多个range来发起【作者:唐霜】本文版权归作者所有,未经授权不得转载。多个请求,因此,每一个range请求返回【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。的结果其实都应该不一样。这也是我第一次调【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。整代码后,留下了尾巴,带来的问题。

著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshua【作者:唐霜】转载请注明出处:www.tangshuang.netng.net【版权所有,侵权必究】

这就意味着,我们后端代码中,必须通过Ra著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】nges头来判断请求处于哪一个阶段,并且原创内容,盗版必究。【作者:唐霜】根据实际情况返回Content-Leng【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】th,否则就有可能在第一次连接时就由于代【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。码疏忽导致相应失败。

【版权所有,侵权必究】【访问 www.tangshuang.n【版权所有,侵权必究】原创内容,盗版必究。et 获取更多精彩内容】未经授权,禁止复制转载。转载请注明出处:www.tangshua【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.netng.net

而比较坑爹的是,safari和chrom【本文首发于唐霜的博客】本文版权归作者所有,未经授权不得转载。e的video逻辑不同。上面这套逻辑适用【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】于safari,但在chrome中,似乎【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。容忍的range体积大很多,我测试了几个【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。视频,都是直接Range: bytes 0-,意思是请求整个视频,而此时如何返回20未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net6的话,chrome又无法播放视频。真的【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】是造孽了……不过好在,遇到这种情况的时候原创内容,盗版必究。本文作者:唐霜,转载请注明出处。,直接返回200,就可以正常播放,于是才著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。有了上面代码中的特殊逻辑。

本文作者:唐霜,转载请注明出处。【转载请注明来源】原创内容,盗版必究。原创内容,盗版必究。

以上就是解决整个问题的完整思路。

著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshua转载请注明出处:www.tangshuang.net原创内容,盗版必究。ng.net本文版权归作者所有,未经授权不得转载。【原创不易,请尊重版权】
【访问 www.tangshuang.n【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.netet 获取更多精彩内容】【版权所有】唐霜 www.tangshu本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】ang.net著作权归作者所有,禁止商业用途转载。【转载请注明来源】

2025-08-08 2246

为价值买单,打赏一杯咖啡

本文价值22.46RMB