服务器不支持Range头时,浏览器如何仅获取图片前1300字节生成占位符?
问题
我希望在图片完全加载前,仅从URL获取1300字节的图片来生成占位符。针对一张2.12KB的图片,我尝试使用XMLHttpRequest的progress事件:
req.addEventListener("progress", (ev) => { console.log("loaded bytes", ev.loaded); // 2179 })
但第一次触发事件时,ev.loaded的值为2179,即整个文件已下载,这不符合我的需求。而使用Python的requests库开启stream模式并设置chunk_size=1300时,成功将1300字节写入文件:
with requests.get(url , stream=True) as response: for chunk in response.iter_content(chunk_size=1300): print(len(chunk)) # 1300 with open("test.jpg" , "wb") as f: f.write(chunk) break
假设服务器不接受Range头,请问浏览器中是否有对应的API可以实现该功能?
回答
浏览器中没有像Python requests那样能精准控制只获取指定字节的原生API,这是因为浏览器的HTTP请求处理受限于底层TCP传输策略、服务器响应方式(比如小文件会一次性发送)以及浏览器缓存机制,很难像后端请求库那样细粒度控制数据流。不过可以通过以下方式实现近似需求:
使用Fetch API结合ReadableStream与AbortController
通过Fetch的响应体ReadableStream逐块读取数据,当累计读取字节达到1300时,立即中断请求,同时截取已读取的前1300字节使用:
const controller = new AbortController(); const targetBytes = 1300; fetch('目标图片URL', { signal: controller.signal }) .then(response => { const reader = response.body.getReader(); let receivedBytes = 0; const chunkList = []; return reader.read().then(function processChunk({ done, value }) { if (done) { // 若文件本身小于1300字节,直接使用全部数据 const buffer = new Uint8Array(receivedBytes); let offset = 0; chunkList.forEach(chunk => { buffer.set(chunk, offset); offset += chunk.length; }); console.log('文件小于目标字节数,已获取全部:', receivedBytes); // 这里用buffer生成占位符 return; } receivedBytes += value.length; chunkList.push(value); if (receivedBytes >= targetBytes) { // 达到目标字节数,中断请求 controller.abort(); // 截取前1300字节 const limitedBuffer = new Uint8Array(targetBytes); let offset = 0; for (const chunk of chunkList) { const takeLength = Math.min(chunk.length, targetBytes - offset); limitedBuffer.set(chunk.subarray(0, takeLength), offset); offset += takeLength; if (offset >= targetBytes) break; } console.log('已获取目标字节数:', offset); // 这里用limitedBuffer生成占位符 } else { // 继续读取下一块 return reader.read().then(processChunk); } }); }) .catch(err => { if (err.name !== 'AbortError') { console.error('请求异常:', err); } });
局限性说明
对于2.12KB这类小文件,服务器大概率会一次性发送完整响应,此时浏览器会直接接收全部数据,即使中断请求也已经拿到了整个文件。但这种情况下,你依然可以在客户端只截取前1300字节来生成占位符,同样能满足需求——只是会多下载几百字节的冗余数据。
内容的提问来源于stack exchange,提问作者Momo
相关产品推荐
相关产品推荐

