【问题标题】:Submitting multipart/form-data in ScalaWS在 ScalaWS 中提交 multipart/form-data
【发布时间】:2017-09-30 00:35:37
【问题描述】:

我正在尝试创建一个包含两部分的帖子:第一部分是 json 文本,第二部分是二进制音频内容。

发帖的代码其实是:

val ref = UUID.randomUUID()
val requestJobData = s"""
{
   "reference": "$ref",
   "operating_mode": "accurate",
   "callback_url": "http://localhost:8100/",
   "model": { "name": "por-bra" },
   "channels": {
       "firstChannelLabel": {
           "result_format": "transcript",
           "format":"audio/x-wav",
            "num_speakers":2,
        }
   }
}
  """
val jsonPart = DataPart("json", requestJobData)
val filePart = FilePart("firstChannelLabel", "audio(1).wav", Some("audio/x-wav"), FileIO.fromPath(Paths.get("C:\\Input\\_pending\\audio(1).wav")))
val body = Source(filePart :: jsonPart :: List())

val response  =
  client.url(s"$baseUrl")
    .post(body)
    .map {response => response.body[String]}

当我尝试这段代码时,我得到了这些错误:

Error:(73, 14) Cannot find an instance of akka.stream.scaladsl.Source[Product with Serializable with play.api.mvc.MultipartFormData.Part[akka.stream.scaladsl.Source[akka.util.ByteString,scala.concurrent.Future[akka.stream.IOResult]]],akka.NotUsed] to WSBody. Define a BodyWritable[akka.stream.scaladsl.Source[Product with Serializable with play.api.mvc.MultipartFormData.Part[akka.stream.scaladsl.Source[akka.util.ByteString,scala.concurrent.Future[akka.stream.IOResult]]],akka.NotUsed]] or extend play.api.libs.ws.ahc.DefaultBodyWritables
        .post(body)

Error:(73, 14) not enough arguments for method post: (implicit evidence$3: play.api.libs.ws.BodyWritable[akka.stream.scaladsl.Source[Product with Serializable with play.api.mvc.MultipartFormData.Part[akka.stream.scaladsl.Source[akka.util.ByteString,scala.concurrent.Future[akka.stream.IOResult]]],akka.NotUsed]])scala.concurrent.Future[play.api.libs.ws.StandaloneWSRequest#Response].
Unspecified value parameter evidence$3.
        .post(body)

我的依赖是:

scalaVersion := "2.12.1"

libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.0" % Test
libraryDependencies += ws
libraryDependencies += guice

libraryDependencies += "com.typesafe" % "config" % "1.3.1"
libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor" % "2.5.3",
  "com.typesafe.akka" %% "akka-testkit" % "2.5.3" % Test
)


libraryDependencies += "com.typesafe.play" %% "play-ahc-ws-standalone" % "1.0.0"
libraryDependencies += "com.typesafe.play" %% "play-ws-standalone-json" % "1.0.0"

libraryDependencies ++= Seq(
  "com.github.pureconfig" %% "pureconfig" % "0.7.2"
)

有人可以帮忙吗?提前致谢!

【问题讨论】:

  • 我在同一条船上。经过一番研究,我相信 WS Play 的独立版本还不包括对多部分请求的支持。请参阅此 github 问题:github.com/playframework/play-ws/issues/126 您会收到编译错误,因为不存在合适的 BodyWritable。
  • 没错。我也遇到了 BodyWritable 的问题。我用我当前的设置回答了这个问题,使用另一个库。

标签: scala playframework


【解决方案1】:

由于我需要更快地完成这项任务,因此对于这个特定部分,我不得不切换到另一个名为 apache.http (http://hc.apache.org/httpcomponents-client-ga/) 的库

这些是我当前的设置:

build.sbt

libraryDependencies ++= Seq(
   "org.apache.httpcomponents" % "httpclient" % "4.3.1",
   "org.apache.httpcomponents" % "httpmime" % "4.3.1"
)

完整的 POST 示例:

import org.apache.http.client.methods.{HttpGet, HttpPost}
import org.apache.http.entity.ContentType
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils

val ref = UUID.randomUUID()
val requestJobData =
  s"""
{
   "reference": "$ref",
   "operating_mode": "accurate",
   "model": { "name": "por-bra" },
   "channels": {
       "firstChannelLabel": {
           "result_format": "lattice",
           "format":"audio/x-wav",
            "num_speakers":2
        }
   }
}
  """

val entity = MultipartEntityBuilder.create()
entity.addTextBody("json", requestJobData, ContentType.APPLICATION_JSON)

val path = Paths.get(audioPath)
val fileName = path.getFileName().toString()
val fileStream = new FileInputStream(audioPath)
entity.addBinaryBody("firstChannelLabel", fileStream, ContentType.create("audio/x-wav"), fileName)
val client = HttpClients.createDefault()
try {
  val post = new HttpPost(baseUrl)
  post.setEntity(entity.build())
  val response = client.execute(post)
}
catch {
  case e: Throwable =>
    log.error("erro ao agendar job: " + e.toString())
}
finally {
  client.close()
}

真的很有效。我省略了一些关于与参与者通信和其他日志记录的代码部分,但我希望这对任何人都有帮助。

【讨论】:

  • 感谢您提供替代解决方案!
猜你喜欢
  • 1970-01-01
  • 2017-09-20
  • 2017-03-28
  • 2016-04-02
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-15
相关资源
最近更新 更多