什么是服务从一个静态文件的首选方法播放框架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.getFile
和OK.sendFile
,指定要提供的文件吗? 这从来没有在生产中断?
(我的应用程序安装在/some-dir/app1/
我从启动/some-dir/
(无app1/
) -也许一切都会如我,而不是启动应用程序从工作/some-dir/app1/
但我“想知道怎么一个‘应该’做的,服务于从控制器内的静态文件呢?所以,一切始终工作也是在生产服务器上,无论从那里我碰巧启动应用程序)
游戏有这一个内置的方法:
Ok.sendResource("public/admin/file.html", classLoader)
您可以从注入的类加载器Environment
与environment.classLoader
或this.getClass.getClassLoader
。
检查数据流的HTTP响应文档
def index = Action {
Ok.sendFile(
content = new java.io.File("/tmp/fileToServe.pdf"),
fileName = _ => "termsOfService.pdf"
)
}
你可以添加一些随机字符串的fileName
(个别为每个登录的用户),以避免认证和非authinticated用户之间共享下载的链接,也使先进的下载统计。
我这样做(但请参见下面的更新 !)
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
这样做的手工方法如下:
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"""")
另一种变体,而无需使用一个字符串,而是通过流媒体文件内容:
def myStaticRessource() = Action { implicit request =>
val contentStream = this.getClass.getResourceAsStream("/public/content.html")
Ok.chunked(Enumerator.fromStream(contentStream)).as(HTML)
}