你需要知道Content-Range:developer.mozilla.org/zh-CN/docs/…
在开发一个类似哔哩哔哩的视频网站时,在实现视频下载接口时发现,前端没办法调整进度。
下面是初始代码:
val bytes = //视频字节流
response.contentType = minIOFile.contentType//设置内容类型
response.setContentLength(bytes.size)//设置内容长度
response.outputStream.write(bytes)//写入字节流
response.outputStream.flush()
之后通过百度了解到了Content-Range,遂加入了以下代码
val bytes = //视频字节流
val fileSize = bytes.size//文件大小
var start = 0
var end = fileSize
var len = fileSize
request.getHeader("Range")?.let { rangeHeader ->
if (rangeHeader.startsWith("bytes=")) {
val range = rangeHeader.substring(6)
val (rStart, rEnd) = range.split("-").map { it.toIntOrNull() }
start = rStart?.coerceAtLeast(0) ?: 0
end = rEnd?.coerceAtMost(fileSize - 1) ?: (fileSize - 1)
len = end - start + 1
}
}
response.setContentLength(len)
response.setHeader("Accept-Ranges", "bytes")
response.setHeader("Content-Range", "bytes $start-$end/$fileSize")
response.outputStream.write(bytes,start,end)//写入字节流
response.outputStream.flush()
发现进度可以调整了,但跨度一大或者倒回去播放就失败了。
之后继续查询,发现了需要修改状态为HttpServletResponse.SC_PARTIAL_CONTENT,
然后额外加入了
response.setContentLength(len)
response.setHeader("Accept-Ranges", "bytes")
response.setHeader("Content-Range", "bytes $start-$end/$fileSize")
response.status = HttpServletResponse.SC_PARTIAL_CONTENT//修改状态码
response.outputStream.write(bytes,start,end)//写入字节流
response.outputStream.flush()
此后前端直接无法播放了,HttpServletResponse.SC_PARTIAL_CONTENT实际状态码为206,是属于请求成功的范畴的,但为什么会被视频播放器认为是请求失败?
令人疑惑。
然后一通摸索,发现一开始返回200,此后返回206,就可以了!
下面是最后的代码:
val bytes = //视频字节流
val fileSize = bytes.size
var start = 0
var end = fileSize
var len = fileSize
response.contentType = minIOFile.contentType
response.setContentLength(len)
response.setHeader("Accept-Ranges", "bytes")
response.setHeader("Content-Range", "bytes $start-$end/$fileSize")
response.status = HttpServletResponse.SC_OK
bytes.forEachIndexed { index, byte ->
if (index >= start) {
response.outputStream.write(byte.toInt())
response.status = HttpServletResponse.SC_PARTIAL_CONTENT
}
}
response.outputStream.flush()
问题解决!