(问题分析与解决方案军为AI协助生成)
一、背景
前端的音频组件使用后端返回的CDN预签名链接访问音频。通过分片请求获得音频数据。在首次访问时,浏览器没有本地缓存,分片请求内容如下:
完成首次音频加载后,浏览器有本地缓存。此时请求音频分片会携带缓存验证头检查资源是否有修改。此时出现了net::ERR_BLOCKED_BY_ORB问题:
二、音频分片加载流程详解
首先我们先理清楚音频的整个加载流程。
1. 首次无缓存请求(正常情况)
流程步骤:
浏览器 → CDN → OSS
↓
浏览器发送GET请求(可能带Range头)
↓
CDN检查缓存(X-Cache: MISS,未命中)
↓
CDN回源到OSS获取数据
↓
OSS返回206 Partial Content + 音频分片数据
↓
浏览器接收数据,开始播放,并缓存响应头和响应体
关键点:
- 请求头:Range: bytes=0-(请求整个文件或特定范围)
- 响应状态:206 Partial Content(分片响应)
- 响应头包含:
- Content-Range: bytes 0-67799(范围信息)
- Content-Length: 67800(本次分片大小)
- Content-Type: application/octet-stream(当前是通用二进制,应为audio/mpeg)
- Etag 和 Last-Modified(用于后续缓存验证)
2. 启用缓存后的请求流程
场景A:请求新的音频片段(应返回206)
用户拖动进度条到新位置
↓
浏览器发送GET请求,带新的Range头
↓
同时带上缓存验证头:If-None-Match 和 If-Modified-Since
↓
CDN/OSS检查:资源未修改,但请求的是新范围
↓
应该返回:206 Partial Content + 新范围的数据
↓
但实际可能返回:304 Not Modified(这是问题所在!)
场景B:请求已缓存的片段(应返回304)
浏览器请求已缓存过的范围
↓
带上If-None-Match和If-Modified-Since
↓
CDN/OSS检查:资源未修改
↓
返回:304 Not Modified(无响应体)
↓
浏览器使用本地缓存的数据
问题现象:
- 206请求失败:ERR_BLOCKED_BY_ORB
- 304请求失败:ERR_BLOCKED_BY_ORB
三、HTTP请求/响应头参数详解
- 状态码
- 200 OK:完整资源返回
- 206 Partial Content:返回部分内容(Range请求)
- 304 Not Modified:资源未修改,使用缓存
- 关键请求头
-
Range: bytes=start-end
- 示例:Range: bytes=0-1023(请求前1024字节)
- 用途:分片加载
-
If-None-Match: "etag值"
- 用途:缓存验证(资源未变则返回304)
-
If-Modified-Since: 日期时间
- 用途:基于时间的缓存验证
-
Sec-Fetch-Dest: audio
- 含义:浏览器期望获取音频资源
-
Sec-Fetch-Mode: no-cors
- 含义:不进行CORS预检(媒体标签常用)
-
Referer:
- 含义:请求来源页面(用于跨域判断)
- 关键响应头
-
Content-Type: application/octet-stream
- 问题:应为audio/mpeg,当前是通用二进制
- 影响:浏览器无法准确识别媒体类型
-
Content-Range: bytes start-end/total
- 示例:bytes 0-1023/10000
- 用途:告知本次分片范围
- Cache-Control: no-cache
- 含义:每次使用缓存前需验证
-
Access-Control-Allow-Origin
- 当前:缺失
- 需要:应包含允许的源(如xxx.xxx.com)或*
-
Access-Control-Allow-Headers: *
- 含义:允许的请求头
-
Access-Control-Allow-Methods: *
- 含义:允许的HTTP方法
-
Etag: "唯一标识"
- 用途:资源版本标识,用于缓存验证
-
Last-Modified: 日期时间
- 用途:资源最后修改时间
四、net::ERR_BLOCKED_BY_ORB 是什么?
ORB(Opaque Response Blocking) 是浏览器的安全机制,用于防止跨域信息泄露。
触发条件(同时满足):
- 跨域请求(不同源)
- 响应缺少Access-Control-Allow-Origin头
- Content-Type不匹配预期(如期望audio/*但收到application/octet-stream)
为什么会被阻止:
- 浏览器无法确认资源是否可被跨域访问
- 通用二进制类型可能被误用,存在信息泄露风险
- 因此阻止JavaScript访问该资源
五、问题根因分析结合你的场景,主要原因如下:
- Content-Type错误(主要原因)
// 当前返回的Content-Type
Content-Type: application/octet-stream ❌
// 应该返回的Content-Type
Content-Type: audio/mpeg ✅
- 浏览器期望audio/*,但收到application/octet-stream
- 触发ORB检查,导致被阻止
-
缺少Access-Control-Allow-Origin头
响应头中缺少: Access-Control-Allow-Origin
-
跨域请求需要明确授权
-
缺少该头会触发ORB
- 304响应处理问题
-
304本身无响应体,但浏览器会复用首次响应的头部
-
如果首次响应的Content-Type和CORS头不正确,后续304也会受影响
六、解决方案
方案一:修正文件上传时的Content-Type
方案二:配置CDN的HTTP响应头
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: Range, Authorization, Content-Type
Access-Control-Expose-Headers: Content-Length, ETag, Content-Range
Access-Control-Max-Age: 86400