【问题标题】:Serving video files from Play 2.1从 Play 2.1 提供视频文件
【发布时间】:2013-08-22 09:18:26
【问题描述】:

我正在尝试创建一个控制器方法,该方法提供由一些类似 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。

【问题讨论】:

    标签: playframework playframework-2.0 streaming httpresponse playframework-2.1


    【解决方案1】:

    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 标头。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-16
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-05
      • 1970-01-01
      相关资源
      最近更新 更多