关于Spring Boot Kotlin进行视频传输时断点续传的问题

364 阅读1分钟

你需要知道Content-Rangedeveloper.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,是属于请求成功的范畴的,但为什么会被视频播放器认为是请求失败image.png 令人疑惑。

然后一通摸索,发现一开始返回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()

问题解决! image.png