Nein
2.6.5
Skala
Mac OS:
Darwin ***.local 17.0.0 Darwin Kernel Version 17.0.0: Thu Aug 24 21:48:19 PDT 2017; root:xnu-4570.1.46~2/RELEASE_X86_64 x86_64
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
scalaVersion := "2.12.3"
"org.scalatestplus.play" %% "scalatestplus-play" % "3.1.1"
Ungültige Anforderung
Für Anfrage 'GET /' [Invalid Json: No content to map due to end of input at [Source: akka.util. ByteIterator$ByteArrayIterator$$anon$1@161d95c6; Zeile: 1, Spalte: 0]]
Bitte suchen Sie das folgende Repository, um das Problem zu reproduzieren:
https://github.com/Abrasha/playframework-issue-example
Danke für den Bericht. Ich werde mir das jetzt mal anschauen.
Hallo @Abrasha , wenn Sie Ihrem Test Typanmerkungen hinzufügen, können Sie sehen, was passiert:
val request: Request[AnyContentAsJson] = FakeRequest()
.withJsonBody(Json.toJson(person))
.withHeaders(CONTENT_TYPE -> JSON)
val acceptAction: Action[JsValue] = homeController.accept
val response: Accumulator[ByteString, Result] = acceptAction.apply(request)
assert(status(response) === CREATED)
Das Problem ist, dass acceptAction.apply
überladen ist – Sie können entweder ein RequestHeader
oder ein Request[JsValue]
übergeben. Da Sie versuchen, ein Request[AnyContentAsJson]
zu übergeben, entspricht dies der RequestHeader
-Version. Dies gibt Accumulator
zurück.
Wenn Sie homeController.accept.apply
aufrufen, erhalten Sie kein Ergebnis zurück, sondern Accumulator[ByteString, Result]
. Wenn Sie status(response)
aufrufen, wird dem Akkumulator ein leeres ByteString
zugeführt, was zu einem Parsing-Fehler führt.
Die Lösung besteht darin, ein Request[JsValue]
zu erstellen, das dem Typ von acceptAction
entspricht. Wenn Sie Request[JsValue]
verwenden, ruft es die richtige Methode accept
auf und gibt Future[Result]
zurück
val request: Request[AnyContentAsJson] = FakeRequest()
.withBody(Json.toJson(person)) // <--- change here
.withHeaders(CONTENT_TYPE -> JSON)
val acceptAction: Action[JsValue] = homeController.accept
val response: Future[Result] = acceptAction.apply(request) // <-- different type here
assert(status(response) === CREATED)
Die alternative Lösung besteht darin, ein AnyContent
BodyParser
zu verwenden – was sowieso der Standard ist. Siehe https://www.playframework.com/documentation/2.6.x/ScalaTestingWithScalaTest#Unit -Testing-EssentialAction für ein Beispiel, wie dies funktioniert. Sie müssen request.body.asJson.get
in Ihrer Aktion verwenden, um das Ergebnis zu erhalten.
Übrigens ist mir klar, dass dies sehr verwirrend ist, aber leider ist es zu schwierig, Play zu ändern, um es weniger verwirrend zu machen. Hier kommen mehrere Designfragen zusammen:
Request
verlängert RequestHeader
- das verursacht überall Probleme, aber wir können es jetzt nicht ändernAction
überlädt die Methode apply
für alles, anstatt Methoden mit separaten Namen zu haben, zB accumulator(rh: RequestHeader)
und invoke(r: Request[T])
AnyContent
sollte nur selten verwendet werden, aber es ist die Standardeinstellung in unserem Code und unserer DokumentationAction
ist auch ein ActionBuilder
– wiederum unter Verwendung apply
-Methoden – und macht es verwirrend zu verstehen, wie Action
s aufgebaut sindIch werde dieses Ticket jetzt schließen, da es wie vorgesehen funktioniert und wir das Design leider nicht ändern können!
@richdougherty Danke für deine Erklärung, du sparst mir viel Zeit :)
Das ist einer meiner Lieblingshasser an Play, die überladende Semantik ist verrückt und schlecht dokumentiert.
Hilfreichster Kommentar
Hallo @Abrasha , wenn Sie Ihrem Test Typanmerkungen hinzufügen, können Sie sehen, was passiert:
Das Problem ist, dass
acceptAction.apply
überladen ist – Sie können entweder einRequestHeader
oder einRequest[JsValue]
übergeben. Da Sie versuchen, einRequest[AnyContentAsJson]
zu übergeben, entspricht dies derRequestHeader
-Version. Dies gibtAccumulator
zurück.Wenn Sie
homeController.accept.apply
aufrufen, erhalten Sie kein Ergebnis zurück, sondernAccumulator[ByteString, Result]
. Wenn Siestatus(response)
aufrufen, wird dem Akkumulator ein leeresByteString
zugeführt, was zu einem Parsing-Fehler führt.Die Lösung besteht darin, ein
Request[JsValue]
zu erstellen, das dem Typ vonacceptAction
entspricht. Wenn SieRequest[JsValue]
verwenden, ruft es die richtige Methodeaccept
auf und gibtFuture[Result]
zurückDie alternative Lösung besteht darin, ein
AnyContent
BodyParser
zu verwenden – was sowieso der Standard ist. Siehe https://www.playframework.com/documentation/2.6.x/ScalaTestingWithScalaTest#Unit -Testing-EssentialAction für ein Beispiel, wie dies funktioniert. Sie müssenrequest.body.asJson.get
in Ihrer Aktion verwenden, um das Ergebnis zu erhalten.Übrigens ist mir klar, dass dies sehr verwirrend ist, aber leider ist es zu schwierig, Play zu ändern, um es weniger verwirrend zu machen. Hier kommen mehrere Designfragen zusammen:
Request
verlängertRequestHeader
- das verursacht überall Probleme, aber wir können es jetzt nicht ändernAction
überlädt die Methodeapply
für alles, anstatt Methoden mit separaten Namen zu haben, zBaccumulator(rh: RequestHeader)
undinvoke(r: Request[T])
AnyContent
sollte nur selten verwendet werden, aber es ist die Standardeinstellung in unserem Code und unserer DokumentationAction
ist auch einActionBuilder
– wiederum unter Verwendungapply
-Methoden – und macht es verwirrend zu verstehen, wieAction
s aufgebaut sindIch werde dieses Ticket jetzt schließen, da es wie vorgesehen funktioniert und wir das Design leider nicht ändern können!