Play Framework解析JSON请求体时异常行为排查求助
排查思路&解决方案
这种情况我在Play Framework(看你提到的Reads/Writes,大概率是用的这个框架)里踩过好几次坑,咱们从几个最常见的方向一步步排查:
1. 自定义Reads里偷偷抛出了异常,fold根本没机会执行
如果你的隐式Reads不是全程用JsError返回校验失败,而是在某些分支直接throw异常,那框架会直接抛出错误,根本走不到你后续的fold逻辑里。
排查&修复示例:
// ❌ 错误写法:解析失败直接抛异常,fold捕获不到 implicit val userReads: Reads[User] = ( (__ \ "username").read[String].map(name => if (name.length < 3) throw new IllegalArgumentException("用户名太短") else name ) )(User.apply _) // ✅ 正确写法:用框架的校验API返回JsError implicit val userReads: Reads[User] = ( (__ \ "username").read[String] .filter(JsonValidationError("用户名长度不能小于3"))(_.length >=3) )(User.apply _)
2. 单元测试的请求模拟有问题,JSON解析提前失败
如果测试里发送的请求不符合要求,框架会在到达你的业务逻辑之前就抛出异常:
- 比如没设置
Content-Type: application/json - 或者发送的JSON本身格式不合法(比如缺引号、逗号写错)
正确测试示例(Play Specs2):
"当JSON校验失败时返回BadRequest" in { val invalidJson = Json.parse("""{"username": "ab"}""") val request = FakeRequest(POST, "/api/user") .withHeaders(CONTENT_TYPE -> JSON) // 一定要加这个头 .withJsonBody(invalidJson) val result = route(app, request).get status(result) mustEqual BAD_REQUEST }
3. fold的错误分支逻辑写错了
有可能你以为自己在错误分支返回了BadRequest,但实际代码里要么抛了异常,要么返回了其他状态码。
排查点:
检查你的fold代码是不是类似下面的错误写法:
// ❌ 错误:错误分支直接抛异常,测试会捕获到RuntimeException request.body.asJson.validate[User].fold( errors => throw new RuntimeException("参数错误"), user => Ok(Json.toJson(user)) ) // ✅ 正确:返回BadRequest响应 request.body.asJson.validate[User].fold( errors => BadRequest(Json.obj("errors" -> JsError.toJson(errors))), user => Ok(Json.toJson(user)) )
4. 全局异常处理器拦截了错误
如果你的应用配置了全局异常处理器,可能会把JsError或者自定义校验异常转换成了其他响应,甚至直接抛出异常而不是返回BadRequest。
排查:
检查全局异常处理器的代码,确保它不会拦截JSON解析相关的错误,比如:
// 确保全局处理器里对JsError的处理是返回BadRequest override def onServerError(request: RequestHeader, exception: Throwable): Result = { exception match { case e: JsResultException => BadRequest(Json.obj("error" -> e.errors.mkString)) case _ => super.onServerError(request, exception) } }
内容的提问来源于stack exchange,提问作者joesan
相关产品推荐
相关产品推荐

