【问题标题】:Play Framework: How to implement REST API for File UploadPlay Framework:如何实现文件上传的 REST API
【发布时间】:2014-05-05 04:52:45
【问题描述】:

我正在使用 Play 2 开发一个 REST API,我想知道如何实现文件上传功能。

我已经阅读了official Play documentation,但它只提供了一个multipart/form-data 示例,而我的后端没有提供任何形式……它只包含一个由 JavaScript 客户端或其他任何东西调用的 REST API。

也就是说,实现此类 API 的正确方法是什么?我应该实现PartHandler,然后仍然使用mutipartFormData 解析器吗?我应该如何将文件内容传递给 API?有没有关于这个主题的详尽示例?

任何帮助将不胜感激。

【问题讨论】:

    标签: javascript scala rest file-upload playframework


    【解决方案1】:

    您应该查看 BodyParsers:http://www.playframework.com/documentation/2.2.x/ScalaBodyParsers

    您尝试做的事情并不是特别复杂,尤其是当您只处理适合内存的较小文件时。毕竟上传文件只是将文件作为 POST 的正文或类似的东西发送。这与在请求中接收一些 XML 或 JSON 没有什么不同。

    【讨论】:

    • 谢谢...我已经知道这份文件了。真正的问题是“我应该如何将文件内容传递给 API?”我认为将正文中的整个文件编码为 base-64 并不是一个好主意,尤其是在文件很大的情况下。我缺少的是如何让客户端/浏览器在没有表单的情况下发送文件块。
    • 所以您的问题更多是关于客户端,而不是 Play 能做什么或不能做什么。我不明白为什么你不能只发送一个将文件作为正文的 POST 请求——而不用 base64 编码——这有什么意义呢? Play 在动作中只接收一大块字节没有问题,这实际上是基本行为。
    • 也许我遗漏了什么...不需要二进制文件以 base-64 编码?
    【解决方案2】:

    希望对你有帮助

    import org.apache.http.entity.mime._
    import java.io.File
    
    import org.apache.http.entity.mime.content._
    import java.io.ByteArrayOutputStream
    import play.api.libs.ws.WS
    
    
    
    val contents ="contents string"
    val file = File.createTempFile("sample", ".txt")
    
    val bw = new java.io.BufferedWriter(new java.io.FileWriter(file)
    bw.write(new_contents);
    bw.close();
    
    builder.addPart("file", new FileBody(file, org.apache.http.entity.ContentType.create("text/plain"), "sample"))
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    val entity = builder.build
    
            val outputstream = new ByteArrayOutputStream
            entity.writeTo(outputstream)
            val header = (entity.getContentType.getName -> entity.getContentType.getValue)
            val response = WS.url("/post/file").withHeaders(header).post(outputstream.toByteArray())
    

    【讨论】:

      【解决方案3】:

      要传递您的内容,根据您的客户端,您可以在客户端将内容编码为 Base64 以将内容作为 Json 传递(您可以使用 Json 正文解析器)。然后在服务器端,您可以使用 Base64 解码器(例如 Apache Commons)解码内容以获取字节数组。就像

      一样简单
      Base64.decodeBase64(YourEncodedFileContent)
      

      当您拥有字节数组时,您可以简单地将其写入磁盘或将其保存到数据库等。我们在生产中使用这种方法,它工作正常,但是我们只处理小文件上传。

      【讨论】:

        【解决方案4】:

        好的,谢谢大家的建议...以下是我解决问题的方法:

        object Files extends Controller {
        
          def upload = SecuredAction[Files.type]("upload").async(parse.multipartFormData(partHandler)) { implicit request =>
            future { request.body.files.head.ref match {
              case Some((data, fileName, contentType)) => Ok(success(Json.obj("fileName" -> fileName)))
              case _ => BadRequest
            }}.recover { case e =>
             InternalServerError(error(errorProcessingRequest(e.getMessage)))
            }
          }
        
          ...
        
          private def partHandler = {
            parse.Multipart.handleFilePart {
              case parse.Multipart.FileInfo(partName, fileName, contentType) =>
                Iteratee.fold[Array[Byte], ByteArrayOutputStream](
                  new ByteArrayOutputStream
                ) { (outputStream, data) =>
                  outputStream.write(data)
                  outputStream
                }.map { outputStream =>
                  outputStream.close()
                  Some(outputStream.toByteArray, fileName, contentType.get)
                }
            }
          }
        }
        

        希望对你有帮助。

        【讨论】:

        • 你能详细说明你在客户端做什么吗? REST 调用的样子以及如何将文件日期发送到服务器?
        • 我不知道你是如何实现你的客户端的......但你可以用 curl 测试它:curl -F "image=@/path/to/your/image.jpg" http://localhost:9000/path/to/your/resource。我希望它有所帮助。
        • @j3d 嗨,我遇到了同样的问题。看起来这是解决方案。但不知道为什么需要创建 PartHandler。你能解释一下为什么吗?我正在使用 Play 2.4,我的客户端正在上传 ajax 文件。
        【解决方案5】:

        虽然我的后端不提供任何形式...它只包含一个由 JavaScript 客户端调用的 REST API

        那么您的后端不是 REST API。您应该遵循 HATEOAS 原则,因此您应该响应每个 GET 请求的链接和表单以及数据。您不必发回 HTML,您可以使用超媒体 json 或 xml 媒体类型来描述这些内容,例如使用 JSON-LD、HAL+JSON、ATOM+XML 等...所以您必须描述您的上传表单在您首选的超媒体中,并让 REST 客户端将该描述转换为真正的 HTML 文件上传表单(如果客户端是 HTML)。之后,您可以像往常一样发送multipart/form-data(REST 与媒体类型无关,因此您可以发送所需的任何媒体类型的数据,而不仅仅是 JSON 格式)。查看AJAX file upload techniques了解更多详情...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-20
          • 2018-02-18
          • 1970-01-01
          • 1970-01-01
          • 2014-07-11
          • 2014-12-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多