我正在尝试创建一个控制器方法,该方法提供由某些类似CMS的数据库条目支持的视频文件。我的控制器方法如下所示:
def getVideo(id: Int) = DBAction { request => implicit dbSession =>
{ for {
dbFile <- fetchDBFile(id)
fsFile <- fetchFilesystemFile(dbFile)
rangeOpt <- request.headers.get(RANGE).map(_.replaceAll("bytes=", "").split("-").toList match {
case rangeStart :: rangeEnd :: Nil => Some(rangeStart.toLong, rangeEnd.toLong)
case rangeStart :: Nil => Some(rangeStart.toLong, fsFile.length())
case _ => None
})
(rangeStart, rangeEnd) <- rangeOpt
} yield SimpleResult(
header = ResponseHeader(
status = PARTIAL_CONTENT,
headers = Map(
CONTENT_TYPE -> MimeTypes.forExtension("mp4").get,
ACCEPT_RANGES -> "bytes",
DATE -> new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(new Date()),
CONTENT_LENGTH -> fsFile.length.toString,
CONTENT_RANGE -> s"bytes $rangeStart-$rangeEnd/${fsFile.length}",
CONNECTION -> "keep-alive"
)
),
body = Enumerator.fromStream(new FileInputStream(fsFile))
)
} getOrElse {
NotFound
}
}
它主要基于two sources来实现处理视频服务所需的特定字节范围请求的逻辑。
在OS X上使用Chrome或Safari访问此控制器方法时,开发人员工具会报告请求已取消 - 未收到任何响应(无论是200还是404)。我已经确认SimpleResponse实际上是由此控制器操作返回的,我希望它能够提供良好的响应,但是Play不会完成响应,或者我的浏览器不接受它。我在这里做错了回应,还是我偶然发现了框架中的错误?
我的Play版本是2.1.3。
答案 0 :(得分:3)
Reasons why Chrome cancels requests.
您使用的来源更为完善。我给你看了我发现的代码:
响应代码并不总是206 PARTIAL_CONTENT:
val responseCode = if (rangeStart != 0 || rangeEnd != fileLength - 1) 206 else 200
缺少跳过字节:
val stream = new FileInputStream(file)
stream.skip(rangeStart) # range starts defaults to 0
内容范围可以是完整文件和部分:
val contentLength = if (responseCode == 206) (rangeEnd - rangeStart + 1) else fileLength
所以你不应该发送每个案例发送Content-Range标题。