从服务2游戏控制器斯卡拉静态/公共/文件(Serving static /public/ file

2019-07-30 22:41发布

什么是服务从一个静态文件的首选方法播放框架2斯卡拉控制器?

该文件捆绑了我的应用程序,所以它不可能硬编码文件系统绝对/path/to/the/file ,因为它的位置取决于在Play应用程式恰好是installeld。

该文件被放置在公共/目录,而不是在应用程序/资产/,因为我不想玩编译它。

(我之所以不只是一个路由添加到该文件,是一个需要访问该文件之前登录,否则是没有用的。)

这是我到目前为止已经完成,但这种打破我的生产服务器上。

object Application ...

  def viewAdminPage = Action ... {
    ... authorization ...
    val adminPageFile = Play.getFile("/public/admin/index.html")
    Ok.sendFile(adminPageFile, inline = true)
  }

而在我的routes文件,我有这样一行:

GET /-/admin/ controllers.Application.viewAdminPage

问题是,我的生产服务器上,这个错误发生:
FileNotFoundException: app1/public/admin/index.html

有一些其他的方法,而不是Play.getFileOK.sendFile ,指定要提供的文件吗? 这从来没有在生产中断?

(我的应用程序安装在/some-dir/app1/我从启动/some-dir/ (无app1/ ) -也许一切都会如我,而不是启动应用程序从工作/some-dir/app1/但我“想知道怎么一个‘应该’做的,服务于从控制器内的静态文件呢?所以,一切始终工作也是在生产服务器上,无论从那里我碰巧启动应用程序)

Answer 1:

游戏有这一个内置的方法:

  Ok.sendResource("public/admin/file.html", classLoader)

您可以从注入的类加载器Environmentenvironment.classLoaderthis.getClass.getClassLoader



Answer 2:

检查数据流的HTTP响应文档

def index = Action {
  Ok.sendFile(
    content = new java.io.File("/tmp/fileToServe.pdf"),
    fileName = _ => "termsOfService.pdf"
  )
}

你可以添加一些随机字符串的fileName (个别为每个登录的用户),以避免认证和非authinticated用户之间共享下载的链接,也使先进的下载统计。



Answer 3:

我这样做(但请参见下面的更新 !)

val fileUrl: java.net.URL = this.getClass().getResource("/public/admin/file.html")
val file = new java.io.File(adminPageUrl.toURI())
Ok.sendFile(file, inline = true)

this是控制器,它是(并且必须)位于同一封装中做为所被服务的文件中。)

这是一个相关的问题: 在Java中的相对路径打开资源

更新

访问通过URI文件导致错误: IllegalArgumentException: URI is not hierarchical ,如果该文件然后位于JAR,如果你运行游戏,像这样是哪种情况里: play stage ,然后target/start

所以不是我读的文件流,它转换为字符串,并发送的字符串作为HTML:

val adminPageFileString: String = {
  // In prod builds, the file is embedded in a JAR, and accessing it via
  // an URI causes an IllegalArgumentException: "URI is not hierarchical".
  // So use a stream instead.
  val adminPageStream: java.io.InputStream =
    this.getClass().getResourceAsStream("/public/admin/index.html")
  io.Source.fromInputStream(adminPageStream).mkString("")
}

...

return Ok(adminPageFileString) as HTML


Answer 4:

这样做的手工方法如下:

val url = Play.resource(file)
url.map { url =>
  val stream = url.openStream()
  val length = stream.available 
  val resourceData = Enumerator.fromStream(stream)

  val headers = Map(
        CONTENT_LENGTH -> length.toString,
        CONTENT_TYPE -> MimeTypes.forFileName(file).getOrElse(BINARY),
        CONTENT_DISPOSITION -> s"""attachment; filename="$name"""")

  SimpleResult(
    header = ResponseHeader(OK, headers), 
    body = resourceData)

使用资产控制器相当于是这样的:

val name = "someName.ext"

val response = Assets.at("/public", name)(request)
response
  .withHeaders(CONTENT_DISPOSITION -> s"""attachment; filename="$name"""")


Answer 5:

另一种变体,而无需使用一个字符串,而是通过流媒体文件内容:

def myStaticRessource() = Action { implicit request =>

  val contentStream = this.getClass.getResourceAsStream("/public/content.html")

  Ok.chunked(Enumerator.fromStream(contentStream)).as(HTML)

}


文章来源: Serving static /public/ file from Play 2 Scala controller