音频分片请求出现跨域资源阻塞(ORB - Opaque Response Blocking) 问题

117 阅读4分钟

(问题分析与解决方案军为AI协助生成)

一、背景

前端的音频组件使用后端返回的CDN预签名链接访问音频。通过分片请求获得音频数据。在首次访问时,浏览器没有本地缓存,分片请求内容如下:

image.png

image.png

完成首次音频加载后,浏览器有本地缓存。此时请求音频分片会携带缓存验证头检查资源是否有修改。此时出现了net::ERR_BLOCKED_BY_ORB问题:

Attached_image.png

image.png

二、音频分片加载流程详解

首先我们先理清楚音频的整个加载流程。

1. 首次无缓存请求(正常情况)

流程步骤:

浏览器 → CDN → OSS
  ↓
浏览器发送GET请求(可能带Range头)
  ↓
CDN检查缓存(X-CacheMISS,未命中)
  ↓
CDN回源到OSS获取数据
  ↓
OSS返回206 Partial Content + 音频分片数据
  ↓
浏览器接收数据,开始播放,并缓存响应头和响应体

image.png 关键点:

  • 请求头: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请求/响应头参数详解

  1. 状态码
  • 200 OK:完整资源返回
  • 206 Partial Content:返回部分内容(Range请求)
  • 304 Not Modified:资源未修改,使用缓存
  1. 关键请求头
  • 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:

    • 含义:请求来源页面(用于跨域判断)
  1. 关键响应头
  • 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) 是浏览器的安全机制,用于防止跨域信息泄露。

触发条件(同时满足):
  1. 跨域请求(不同源)
  2. 响应缺少Access-Control-Allow-Origin头
  3. Content-Type不匹配预期(如期望audio/*但收到application/octet-stream)
为什么会被阻止:
  • 浏览器无法确认资源是否可被跨域访问
  • 通用二进制类型可能被误用,存在信息泄露风险
  • 因此阻止JavaScript访问该资源

五、问题根因分析结合你的场景,主要原因如下:

  1. Content-Type错误(主要原因)
    // 当前返回的Content-Type

    Content-Type: application/octet-stream  ❌

    // 应该返回的Content-Type  

    Content-Type: audio/mpeg  ✅

  • 浏览器期望audio/*,但收到application/octet-stream
  • 触发ORB检查,导致被阻止
  1. 缺少Access-Control-Allow-Origin头

    响应头中缺少: Access-Control-Allow-Origin

  • 跨域请求需要明确授权

  • 缺少该头会触发ORB

  1. 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