Chromium浏览器Range请求是否存在分片大小限制?如何解决
问题场景
通过Range请求分片拉取服务端大体积3D模型文件,所有分片下载完成后拼接为完整ArrayBuffer,传入Cesium完成模型加载,核心实现代码如下:
const m = 1024 * 1024 * 3; Axios({ url: option.url, method: 'head' }).then((res) => { const size = Number(res.headers['content-length']); const length = parseInt(size / m); const arr = [] for (let i = 0; i < length; i++) { let start = i * m; let end = (i == length - 1) ? size - 1 : (i + 1) * m - 1; arr.push(this.downloadRange(option.url, start, end, i)) } Promise.all(arr).then(res => { const arrBufferList = res.sort(item => item.i - item.i).map(item => new Uint8Array(item.buffer)); const allBuffer = this.concatenate(Uint8Array, arrBufferList); primitive = viewer.scene.primitives.add( new Cesium.Model({ gltf: allBuffer, show: true, modelMatrix: modelMatrix, scale: parseFloat(option.scale) || 1, }) ); }) })
分片下载方法downloadRange实现如下:
downloadRange(url, start, end, i) { return new Promise((resolve, reject) => { const req = new XMLHttpRequest(); req.open("GET", url, true); req.setRequestHeader("range", `bytes=${start}-${end}`); req.responseType = "blob"; req.onload = function (oEvent) { req.response.arrayBuffer().then((res) => { resolve({ i, buffer: res, }); }); }; req.send(); }); }
异常表现
- 分片参数
m设置为小于6MB(即1024*1024*6)时,所有请求正常返回,流程无异常 - 分片大小
m超过6MB阈值时,浏览器抛出GET <url> net::ERR_FAILED 206 (Partial Content)错误,请求直接失败 - Postman调用同接口请求30MB大小的分片可正常返回,可排除服务端Range支持故障
- 异常在Chrome、Edge等Chromium内核浏览器可稳定复现
问题根因
该异常和Chromium内核本身的Range请求大小限制无关,核心诱因有两点:
- 实现逻辑中使用
Promise.all一次性发起全部分片请求,没有做并发控制。Chromium内核默认对同域名下的普通请求设置6个左右的并发连接上限,针对响应体体积超过5MB的大体积请求,为了管控标签页内存占用,允许的并发数会进一步降低到2-3个,超出并发阈值的请求会被浏览器直接拦截抛出ERR_FAILED,根本不会发送到服务端。 - 代码中使用XHR接收Blob类型响应,需要等整个分片响应完全接收完成后才会生成Blob对象、进一步转ArrayBuffer,当分片体积超过6MB时,Chromium的Blob存储机制会触发单Blob内存阈值校验,瞬时内存占用过高时会直接中断请求。
Postman作为独立桌面应用,没有浏览器的并发连接限制、沙箱内存配额限制,因此大分片请求可以正常返回。
规避方案
- 优先使用Cesium原生加载能力:直接将模型资源URL传入Cesium.Model构造函数,Cesium内部已实现成熟的大模型流式Range加载逻辑,自带并发控制、缓存、断点续传能力,稳定性和加载性能远高于手动实现的分片逻辑。
- 添加并发控制:如果必须手动分片,不要用
Promise.all一次性发起所有请求,实现简单的请求并发池,将同时间进行的分片请求数控制在2-3个,完成一个再发起下一个,避免触发浏览器并发管控阈值。 - 调整分片大小:将单分片大小固定在4-5MB区间,这个区间是Chromium内核下验证过的安全阈值,既不会产生过多请求开销,也不会触发大响应的内存拦截机制。
- 替换请求实现:将XHR+Blob的实现替换为Fetch API的流式读取,通过
response.body.getReader()边接收边写入缓冲区,不需要等待整个响应生成Blob,可绕过单Blob的内存阈值限制。
内容的提问来源于stack exchange,提问作者John_Doe
相关产品推荐
相关产品推荐

