问题
In routes:
POST /login controllers.ApplicationCtrl.login()
In Controller:
def login = Action(parse.json) { implicit request => {
val email = (request.body \ "email").as[String]
val password = (request.body \ "password").as[String]
Ok(Json.toJson(
Map("status" -> "OK",
"message" -> "%s created".format(email))
))
}
In tests
"login" in new WithApplication{
val request = route( FakeRequest(
Helpers.POST,
controllers.routes.ApplicationCtrl.login.url,
FakeHeaders(Seq(CONTENT_TYPE -> Seq("application/json"))),
""" {"email" : "bob@mail.com", "password" : "secret"} """
)).get
status(request) must equalTo(OK)
}
When I test using command line:
curl --header "Content-type: application/json" --request POST --data '{"email" : "bob@mail.com", "password" : "secret"}' http://localhost:9000/login
It gets desirable response.
{"status":"OK","message":"bob@mail.com created"}
But the test returns 400 error.
What's wrong?
(command line test wins by simplicity and understandability)
回答1:
What's happening here is that Play sets the content type of the request according to the type of the body. You're using a string body so that the content type header you're setting is later overridden by text/plain; charset=utf-8
.
Because you're explicitly parsing the body as Json the body parser will return a bad request 403 if the content type is not either text/json
or application/json
.
The best thing to do in your case is to use a Json body, i.e:
"login" in new WithApplication {
val request = route( FakeRequest(
POST,
controllers.portal.routes.Portal.test.url,
FakeHeaders(Seq.empty),
play.api.libs.json.Json.obj("email" -> "bob@mail.com", "password" -> "secret")
)).get
status(request) must equalTo(OK)
}
Note that you can make that a bit more succinct by letting an alternate FakeRequest
constructor infer the method and URL of your action from the call:
val request = route(FakeRequest(controllers.portal.routes.Portal.test)
.withBody(Json.obj("email" -> "bob@mail.com", "password" -> "secret"))).get
Data types you can use as the body parameter and their content type mapping:
JsValue
->application/json
NodeSeq
->text/xml
String
->text/plain
Map[String, Seq[String]]
->application/x-www-form-urlencoded
Array[Byte]
-> nothing
There's also the option of using the tolerantJson
as a body parser to skip checking the content type completely.
来源:https://stackoverflow.com/questions/28247112/playframework-fakerequest-returns-400-error