先上代码:
前端代码, fetch请求
const rangeImge = () => {
const totalSize = 924087
const chunkSize = 300000
const numChunks = Math.ceil(totalSize / chunkSize)
let chunk = new Blob()
let index = 0
send()
function send() {
if (index >= numChunks) return
const start = index * chunkSize
const end = Math.min(start + chunkSize - 1, totalSize - 1)
fetch('imageurl', {
headers: { Range: `bytes=${start}-${end}` },
})
.then((response) => {
return response.blob()
})
.then((blob) => {
index++
send()
chunk = new Blob([chunk, blob], { type: 'image/png' })
const url = URL.createObjectURL(chunk)
console.log(111, chunk)
image.src = url
})
}
}
后端 node koa2代码
router.get('/imageRange', async (ctx) => {
const filePath = path.join(__dirname, 'image.png')
const stat = fs.statSync(filePath)
const fileSize = stat.size
ctx.set('Content-Type', 'image/png')
ctx.set('Accept-Ranges', 'bytes')
const rangeHeader = ctx.header.range
if (rangeHeader) {
const parts = rangeHeader.replace(/bytes=/, '').split('-')
const start = parseInt(parts[0], 10)
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1
const chunkSize = end - start + 1
ctx.status = 206
ctx.set('Content-Range', `bytes ${start}-${end}/${fileSize}`)
ctx.set('Content-Length', chunkSize)
const fileStream = fs.createReadStream(filePath, { start, end })
ctx.body = fileStream
} else {
ctx.set('Content-Length', fileSize)
ctx.body = fs.createReadStream(filePath)
}
})
可以看见发了数个请求,每个请求的请求头都带上了range字段
请求头中会带上一个start 和一个 end 代表要获取的数据范围
响应头中会返回一个content-range字段,告知当前返回的数据范围和总的数据量
然后你就能看到图片从上到下,一点点的拼上去了
要点
- 如果只是想获取start为0, end为任意值的片段,也就是第一个任意大小的片段,可以直接拿到返回的数据,然后直接设置为img的src,不用blob处理,这里是可以直接显示获取的片段的。
- 如果start 不为0, 也就是获取的不是第一个片段,那么必须用blob处理数据,并且还要按照片段顺序拼接好,才能正确的显示图片。
- 也可以用arrayBuffer处理数据的拼接。
- 后端需要自己实现对range的支持。