无效的 Json:使用播放正文解析器时由于输入结束而没有要映射的内容 [英] Invalid Json: No content to map due to end-of-input when using play body parser
问题描述
我正在尝试测试尝试解析请求中发送的 JSON 的控制器方法:
I'm trying to test a controller method that attempts to parse JSON sent in the request:
def addRoomToProfileForTime = Action.async(parse.json[AddRoomToProfileForTimeRequest]) { request =>
profileService.addRoomToProfileForTime(request.body.roomId, request.body.profileId, request.body.timeRange).value.map {
case Xor.Right(_) => Ok
case Xor.Left(err) => BadRequest(Json.toJson(err))
}
}
这是代表请求的案例类:
This is the case class that represents the request:
final case class AddRoomToProfileForTimeRequest(
roomId: Int,
profileId: Int,
timeRange: TimeRange
)
implicit val addRoomToProfileForTimeRequestFormat:Format[AddRoomToProfileForTimeRequest] = Json.format
此代码按预期工作,我发出这样的请求:
This code works as expected with I make a request like so:
curl -H "Content-Type: application/json" -X POST -d '{"roomId":3,"profileId":1,"timeRange":{"id":1,"fromTime":"2000-01-01T01:01","toTime":"2000-01-01T02:01"}}' http://localhost:9000/api/profiles/addRoomToProfileForTime
但我正在尝试为此方法编写测试(请注意,我使用 macwire 进行依赖注入,因此不能使用 WithApplication
:
But I'm trying to write a test for this method (note that I am using macwire for dependency injection, hence cannot use WithApplication
:
"add a room to profile for time" in new TestContext {
val roomId = 1
val profileId = 1
val from = "2000-01-01T01:01"
val to = "2000-01-01T02:01"
val requestJson = Json.obj(
"roomId" -> roomId,
"profileId" -> profileId,
"timeRange" -> Json.obj(
"id" -> 1,
"fromTime" -> from,
"toTime" -> to
)
)
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val fakeReq = FakeRequest(Helpers.POST, "api/profiles/addRoomToProfileForTime")
.withHeaders(CONTENT_TYPE -> "application/json")
.withJsonBody(requestJson)
val result = profileController.addRoomToProfileForTime()(fakeReq).run
val content = contentAsString(result)
println(content)
status(result) must equalTo(OK)
}
但是,此测试因 Play 的错误请求而失败:
However, this test fails with a Bad Request from Play:
<body>
<h1>Bad Request</h1>
<p id="detail">
For request 'POST api/profiles/addRoomToProfileForTime' [Invalid Json: No content to map due to end-of-input at [Source: akka.util.ByteIterator$ByteArrayIterator$$anon$1@37d14073; line: 1, column: 0]]
</p>
</body>
如果我使用 request.body.asJson
解析 JSON,该方法会按预期运行.只是使用上面的正文解析器方法才会出现此错误.
If I parse the JSON with request.body.asJson
the method behaves as expected. It's only using the body parser method above that I get this error.
推荐答案
简短的回答是:在控制器测试中的 FakeRequest
上使用 withBody
方法而不是 <代码>withJsonBody.
The short answer is: on your FakeRequest
in your controller test use the withBody
method instead of withJsonBody
.
我也有这个问题,我尴尬地花了几个小时才弄明白.长的答案是 FakeRequest
的 withJsonBody
返回一个 FakeRequest[AnyContentAsJson]
,并且因为你的控制器期待一个 JsValue
(not 是 AnyContentAsJson
),当您在操作上调用 apply()
时,它无法匹配此应用方法,这是一个你想要:
I had this issue as well, and I embarrassingly spent hours on it until I figured it out. The long answer is that FakeRequest
's withJsonBody
returns a FakeRequest[AnyContentAsJson]
, and since your controller is expecting a JsValue
(not an AnyContentAsJson
), when you call apply()
on your action it fails to match this apply method, which is the one you want:
def apply(request: Request[A]): Future[Result]
和改为点击这个应用方法:
def apply(rh: RequestHeader): Accumulator[ByteString, Result]
因此,由于您没有将任何字节传递给累加器,您会收到意外的 end-of-input
错误消息.
and thus since you're not then passing any Bytes to the Accumulator, you get the unexpected end-of-input
error message you're getting.
这篇关于无效的 Json:使用播放正文解析器时由于输入结束而没有要映射的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!