You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Play WS请求报错:无BodyWritable隐式值,参数构造问题求助

解决Play WS请求构造与序列化报错问题

首先,咱们来拆解你遇到的核心问题:一是样例类的JSON序列化逻辑不符合Play Json规范,二是直接用Map传参导致Play找不到对应的BodyWritable,这两个问题共同引发了那个序列化报错。

问题1:自定义Writes的实现不规范

你当前写的InitVideoUploadParamsWrites和VideoMetadataParamsWrites只是定义了普通的writes方法,并不是Play Json要求的Writes[T]类型。Play的Json序列化机制没法识别这类自定义隐式对象,自然没法帮你把样例类转换成目标JSON结构。

问题2:Map传参引发BodyWritable缺失

调用post(Map(...))时,Play WS找不到如何把这个Map转换成请求体的隐式BodyWritable,这就是报错No implicits found for parameter evidence$2: BodyWritable[Map[String, Object]]的直接原因。


正确解决方案

我们需要修正样例类的序列化逻辑,让Play能正确将对象转换成你需要的JSON结构,然后直接传递对象给post方法即可。

步骤1:修正样例类与Writes实现

推荐用Play Json的自动生成宏来简化实现,既简洁又不易出错:

import play.api.libs.json._

// 对应metadata节点的样例类
case class VideoMetadata(name: String, description: String)
object VideoMetadata {
  implicit val writes: Writes[VideoMetadata] = Json.writes[VideoMetadata]
}

case class VideoMetadataParams(metadata: VideoMetadata)
object VideoMetadataParams {
  implicit val writes: Writes[VideoMetadataParams] = Json.writes[VideoMetadataParams]
}

case class InitVideoUploadParams(videoMetadataParams: VideoMetadataParams)
object InitVideoUploadParams {
  implicit val writes: Writes[InitVideoUploadParams] = Json.writes[InitVideoUploadParams]
}

// 辅助方法:快速创建请求对象
def buildInitUploadParams(name: String, desc: String): InitVideoUploadParams = {
  InitVideoUploadParams(VideoMetadataParams(VideoMetadata(name, desc)))
}

步骤2:重构WS请求代码

现在直接传递InitVideoUploadParams对象给post方法,Play会自动利用隐式的Writes把对象序列化为JSON,同时默认的BodyWritable[JsValue]会帮你处理请求体的转换:

val uploadParams = buildInitUploadParams(fileName, fileName)
ws.url(savaUrl + configObj.get[String]("kaltura.init"))
  .post(uploadParams)

验证生成的JSON结构

上面的代码会生成你需要的目标JSON:

{
  "initVideoUploadParams": {
    "videoMetadataParams": {
      "metadata": {
        "name": "你的文件名",
        "description": "你的文件名"
      }
    }
  }
}

可选:手动实现Writes(如果需要定制)

如果你需要更灵活的序列化逻辑,也可以手动实现Writes接口,比如:

object InitVideoUploadParams {
  implicit val writes: Writes[InitVideoUploadParams] = new Writes[InitVideoUploadParams] {
    override def writes(params: InitVideoUploadParams): JsValue = {
      Json.obj(
        "videoMetadataParams" -> Json.toJson(params.videoMetadataParams)
      )
    }
  }
}

不过宏生成的方式更省心,优先推荐使用。

内容的提问来源于stack exchange,提问作者Manish Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:03:14