【问题标题】:Serving static /public/ file from Play 2 Scala controller从 Play 2 Scala 控制器提供静态 /public/ 文件
【发布时间】:2012-08-09 20:40:16
【问题描述】:

Play Framework 2 Scala 控制器提供静态文件的首选方法是什么?

该文件与我的应用程序捆绑在一起,因此无法硬编码绝对文件系统 /path/to/the/file,因为它的位置取决于 Play 应用程序的安装位置。

文件放在 public/ 目录下,但不在 app/assets/ 下,因为我不想让 Play 编译它。

(我之所以不简单地为该文件添加路由,是因为需要先登录才能访问该文件,否则没有用。)

这是我到目前为止所做的,但这在我的生产服务器上中断了。

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/ 启动应用程序,也许一切都可以工作。但我想知道如何一个“应该”做的,从控制器内部提供静态文件?这样,无论我碰巧从哪里启动应用程序,一切都可以在生产服务器上运行)

【问题讨论】:

    标签: scala playframework-2.0


    【解决方案1】:

    查看Streaming HTTP responses文档

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

    您可以向fileName(每个登录用户单独)添加一些随机字符串,以避免在经过身份验证的用户和未经身份验证的用户之间共享下载链接,并进行高级下载统计。

    【讨论】:

    • 您好 biesior,感谢您的回答。提供的文件是我的 Web 应用程序管理页面的 HTML 文件。该文件与我的应用程序捆绑在一起,并且无法将 /tmp/file 之类的路径硬编码到该文件,因为它的位置取决于 Play 应用程序的安装位置。
    • (我更新了我的问题以澄清该文件与我的应用程序捆绑在一起。)
    • 感谢Streaming HTTP responses 的链接。出于某种原因,我没有考虑该页面(可能是因为我没有想到...流式传输巨大的视频文件)。
    • @KajMagnus - 预览所有文档以了解其他技巧和可能性是个好主意。
    • (是的,我同意 - 我这样做了,但可能是 6 个月前。可能有些事情我已经忘记了)
    【解决方案2】:

    我这样做了:(但请参阅下面的更新!)

    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 是控制器,它(并且必须)位于与所服务的文件相同的包中。)

    这是一个相关的问题:open resource with relative path in java

    更新

    通过 URI 访问文件会导致错误:IllegalArgumentException: URI is not hierarchical,如果文件位于 JAR 中,如果您像这样运行 Play: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
    

    【讨论】:

      【解决方案3】:

      手动方法如下:

      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"""")
      

      【讨论】:

        【解决方案4】:

        另一种变体,不使用字符串,而是通过流式传输文件内容:

        def myStaticRessource() = Action { implicit request =>
        
          val contentStream = this.getClass.getResourceAsStream("/public/content.html")
        
          Ok.chunked(Enumerator.fromStream(contentStream)).as(HTML)
        
        }
        

        【讨论】:

          【解决方案5】:

          Play 有一个内置方法:

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

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

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多