Как отключить ответы об ошибках HTML при использовании Action (parse.json)?

В REST API, реализованном с помощью Play Framework (2.4), я использую _ 1_ для синтаксического анализа JSON из тела входящего запроса POST.

С моим текущим кодом (см. Ниже),

  • Отправка действительного JSON с отсутствующими полями (например, {"foo": ""}) дает 400 с телом ответа {"error":"Missing input fields"}. Это нормально и ожидаемо. ????

  • При публикации полностью недопустимого JSON (например, {,,,} или {\00}) получается 400 с длинным текстом HTML-ответа. ???? Это происходит откуда-то из parse.json.

В последнем случае: как избавиться от тела ответа HTML? Я бы хотел, чтобы тело ответа либо содержало короткое сообщение об ошибке JSON (например, {"error":"Invalid JSON input"}), либо вообще ничего. Есть ли в Play возможность конфигурации для этого, или мне нужно будет создать собственное действие? Какой самый простой способ?

Метод контроллера:

def test = Action(parse.json) { request =>
  request.body.validate[Input].map(i => {
    Ok(i.foo)
  }).getOrElse(BadRequest(errorJson("Missing input fields")))
}

Другие материалы, использованные выше:

case class Input(foo: String, bar: String)

object Input {
  implicit val reads = Json.reads[Input]
}

case class ErrorJson(error: String)

object ErrorJson {
  implicit val writes = Json.writes[ErrorJson]
}

private def errorJson(message: String) = Json.toJson(ErrorJson(message))

person Jonik    schedule 30.09.2016    source источник
comment
Вы пытались переопределить onError метод перехватчика в Global и перехватить возникшее исключение, чтобы настроить сообщение об ошибке?   -  person Richeek    schedule 30.09.2016
comment
В моем приложении нет Global; он устарел в последних версиях Google Play. Вместо этого можно использовать настраиваемый HttpErrorHandler.   -  person Jonik    schedule 03.10.2016
comment
Ах я вижу. Я использую Play 2.4   -  person Richeek    schedule 03.10.2016
comment
Да, я тоже. В 2.4 (и 2.5 afaik) все еще можно использовать многие старые API, которые, тем не менее, устарели / больше не рекомендуются; см. Руководство по переходу на Play 2.4.   -  person Jonik    schedule 04.10.2016
comment
официальный пример: github.com /playframework/play-scala-rest-api-example/blob/2.6.x/ Мне кажется, что Play не поддерживает Rest API.   -  person WeiChing 林煒清    schedule 14.03.2018


Ответы (2)



Короткий ответ: в https://github.com/playframework/playframework/blob/48a76b851946261a952a2edcc4b8dbeeb303e07b/framework/src/play/src/main/scala/play/api/mvc/ContentLypes9.

Json.parse(bytes.iterator.asInputStream)

Json.parse делегирует parseJsValue Jacksons, что вызывает исключение. Я не могу правильно следовать коду, почему исключение не отлавливается должным образом внутри Iteratee фреймворка.

Самым простым решением было бы реплицировать код в ContentTypes.scala, перехватывая исключение около Json.parse и должным образом превращая его в Left значение Iteratee BodyParser. К сожалению, в Play нет строительных блоков, поэтому потребуется много копипаста, если вы хотите сделать это, как в Play.

В качестве альтернативы вы можете сделать тупой Iteratee.fold и направить Json.parse на накопленный массив байтов, это нехорошо; вы, вероятно, захотите проверить заголовки accept, использовать построитель bytearray и ограничить максимальный размер ввода

val betterJson: BodyParser[JsValue] = BodyParser("better json") { _request =>
  import play.api.libs.iteratee.Execution.Implicits.defaultExecutionContext

  Iteratee.fold(new Array[Byte](0)) { (bytes: Array[Byte], acc: Array[Byte]) =>
    bytes ++ acc
  } map { bytes =>
    val res: Either[Result, JsValue] = Try(Json.parse(bytes)) match {
      case Success(v) => Right(v)
      case Failure(e) => Left(BadRequest("bad json"))
    }
    res
  }
}

Использование betterJson в контроллере:

def test = Action(betterJson) { request =>
  request.body.validate[Int].map(i => {
    Ok(i.toString)
  }).getOrElse(BadRequest("my error"))
}

Протестировано с:

// works:
// $ curl -H "Content-Type: application/json" -X POST -d '123' localhost:9000/test
// 123
// $ curl -H "Content-Type: application/json" -X POST -d '{}' localhost:9000/test
// my error
//
// issue:
// $ curl -H "Content-Type: application/json" -X POST -d '.' localhost:9000/test
// bad json
person phadej    schedule 30.09.2016