Javascript Play框架:如何实现文件上传的RESTAPI
我正在用Play2开发一个RESTAPI,我想知道如何实现文件上传功能 我已经阅读了,但它只提供了一个Javascript Play框架:如何实现文件上传的RESTAPI,javascript,scala,rest,file-upload,playframework,Javascript,Scala,Rest,File Upload,Playframework,我正在用Play2开发一个RESTAPI,我想知道如何实现文件上传功能 我已经阅读了,但它只提供了一个多部分/表单数据示例,而我的后端没有提供任何表单。。。它只是由一个RESTAPI组成,由JavaScript客户端或其他任何程序调用 也就是说,实现这样一个API的正确方法是什么?我应该实现一个PartHandler,然后仍然使用multipartformdata解析器吗?如何将文件内容传递给API?关于这个话题有没有详尽的例子 非常感谢您的帮助。您应该了解BodyParser: 您试图做的事情
多部分/表单数据
示例,而我的后端没有提供任何表单。。。它只是由一个RESTAPI组成,由JavaScript客户端或其他任何程序调用
也就是说,实现这样一个API的正确方法是什么?我应该实现一个PartHandler
,然后仍然使用multipartformdata
解析器吗?如何将文件内容传递给API?关于这个话题有没有详尽的例子
非常感谢您的帮助。您应该了解BodyParser:
您试图做的事情并不特别复杂,尤其是当您只处理适合内存的较小文件时。毕竟上传一个文件仅仅是把文件作为帖子的主体或者类似的东西发送。这与在请求中接收一些XML或JSON没有任何区别。您应该研究BodyParser: 您试图做的事情并不特别复杂,尤其是当您只处理适合内存的较小文件时。毕竟上传一个文件仅仅是把文件作为帖子的主体或者类似的东西发送。这与在请求中接收一些XML或JSON没有任何区别 虽然我的后端不提供任何形式。。。它只包含一个由JavaScript客户端调用的RESTAPI 那么您的后端不是RESTAPI。您应该遵循HATEOAS原则,因此您应该使用链接和表单以及数据来响应每个GET请求。您不必发回HTML,您可以使用超媒体json或xml媒体类型来描述这些内容,例如json-LD、HAL+json、ATOM+xml等。。。因此,您必须用首选超媒体描述您的上传表单,并让REST客户端将该描述转换为真正的HTML文件上传表单(如果客户端是HTML)。之后,您可以像往常一样发送一个
多部分/表单数据
(REST是媒体类型无关的,因此您可以以任何想要的媒体类型发送数据,而不仅仅是JSON格式)。有关更多详细信息,请查看
虽然我的后端不提供任何形式。。。它只包含一个由JavaScript客户端调用的RESTAPI
那么您的后端不是RESTAPI。您应该遵循HATEOAS原则,因此您应该使用链接和表单以及数据来响应每个GET请求。您不必发回HTML,您可以使用超媒体json或xml媒体类型来描述这些内容,例如json-LD、HAL+json、ATOM+xml等。。。因此,您必须用首选超媒体描述您的上传表单,并让REST客户端将该描述转换为真正的HTML文件上传表单(如果客户端是HTML)。之后,您可以像往常一样发送一个多部分/表单数据
(REST是媒体类型无关的,因此您可以以任何想要的媒体类型发送数据,而不仅仅是JSON格式)。查看更多详细信息…希望这有帮助
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())
希望这有帮助
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())
要传递内容,根据您的客户端,您可以在客户端将内容编码到Base64,以将内容作为Json传递(您可以使用Json主体解析器)。然后在服务器端,您可以使用Base64解码器(例如Apache Commons)对内容进行解码,以获得字节数组。这将是简单的
Base64.decodeBase64(YourEncodedFileContent)
当您有字节数组时,您可以简单地将其写入磁盘或保存到数据库等。我们在生产中使用这种方法,它工作正常,但我们只处理小文件上传 要传递内容,根据客户端的不同,您可以在客户端将内容编码为Base64,以Json形式传递内容(您可以使用Json主体解析器)。然后在服务器端,您可以使用Base64解码器(例如Apache Commons)对内容进行解码,以获得字节数组。这将是简单的
Base64.decodeBase64(YourEncodedFileContent)
当您有字节数组时,您可以简单地将其写入磁盘或保存到数据库等。我们在生产中使用这种方法,它工作正常,但我们只处理小文件上传 好的,谢谢大家的建议。。。以下是我如何解决我的问题:
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)
}
}
}
}
希望能有帮助。好的,谢谢大家的建议。。。以下是我如何解决我的问题:
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)
}
}
}
}
希望有帮助。谢谢。。。我已经知道这个文件了。真正的问题是“我应该如何将文件内容传递给API?”我不认为将正文中的整个文件编码为base-64是一个好主意,尤其是如果文件很大的话。我缺少的是如何让客户端/浏览器在没有表单的情况下发送文件块。因此,您的问题更多的是关于客户端,而不是Play可以或不能做什么。我不明白为什么不能只发送一个POST请求,而不使用base64编码,这有什么意义?Play在一个动作中只接收一大块字节是没有问题的,这实际上是基本行为。也许我遗漏了什么。。。不需要用base-64编码二进制文件吗?谢谢。。。我已经知道这个文件了。真正的问题是“我应该如何将文件内容传递给API?”我不认为将正文中的整个文件编码为base-64是一个好主意,尤其是如果文件很大的话。我缺少的是如何让客户端/浏览器在没有表单的情况下发送文件块。因此,您的问题更多的是关于客户端,而不是Play可以或不能做什么。我不明白为什么不能只发送一个POST请求,而不使用base64编码,这有什么意义?Play在一个动作中只接收一大块字节是没有问题的,这实际上是基本行为。也许我遗漏了什么。。。不需要二进制文件以base-64编码吗?您能详细说明一下您在客户端所做的工作吗?REST调用看起来如何,以及您如何将文件日期发送到服务器?我不知道您是如何实现您的客户端。。。但是你可以直接测试它