Play Framework 2.5 ajax json route参数async MongoDB

时间:2017-02-19 18:06:29

标签: json ajax routes playframework-2.5

在Play Framework中将json从javascript发布到服务器:

var myJson = {"name": "joe", "age":20};
var obj = JSON.parse(myJson);

$.ajax(jsRoutes.controllers.MyController.create(obj));

现在,我已将javascript路由器配置正常。如果我将obj作为字符串接收,我可以将它打印到控制台就好了。

routes.conf:

POST    /person/add     controllers.MyController.createFromAjax(ajax: String)

但是,我想使用异步承诺将json写入MongoDB,Activator会给出编译时错误:

scala.concurrent.Future[play.api.mvc.Result][error]  cannot be applied to (String)

我有其他路由没有使用Postman接收json的参数并将其写入MongoDB就好了

routes.conf

POST    /heartrates/bulk            controllers.HRController.createFromJson 

如果我省略了从Ajax接收json而不是使用Postman的路由上的参数,我在浏览器中收到HTTP 400错误。

POST http://localhost:9000/person/add 400 (Bad Request)

所以,我的问题是,Ajax需要一个参数但String不会工作。播放文档说json总是以字符串形式接收。我在这做错了什么?

Scala Controller Code取自Lightbend种子Play.Reactive.MongoDB:

def createBulkFromAjax = Action.async(parse.json) { request =>

val documents = for {
  heartRate        <- request.body.asOpt[JsArray].toStream
  maybeHeartRate   <- heartRate.value
  validHeartRate   <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate

for {
  heartRate <- hrFuture
  multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
  Logger.debug(s"Successfully inserted with multiResult: $multiResult")
  Created(s"Created ${multiResult.n} heartRate")
}
}

2 个答案:

答案 0 :(得分:0)

我认为,作为Action调用的一部分传递给jsRoutes的参数与传递给端点的参数(即查询字符串,查询参数等)之间的混淆)。

如果您宣布了一个非可选参数(就像您使用400 Bad Request所做的那样),则播放将返回ajax: String,然后您不会在请求中实际提供该参数。

虽然从概念上讲, obj传递给您的操作,但它不是一个查询参数 - 您已声明您的端点需要HTTP POST - 所以JSON应该在HTTP请求正文。请注意,您的其他端点不接受任何查询参数。

所以第1步是修复您的routes文件(我已将您的方法重命名为与其他现有工作方式相匹配):

POST    /person/add     controllers.MyController.createFromJson

如果您查看Play documentation for the Javascript reverse router,您会看到如果您正在执行GET以外的操作,则需要设置type(也称为HTTP方法)。那么,第2步,这就是你的Javascript实现POST的样子:

var myJson = {"name": "joe", "age":20};
var obj = JSON.stringify(myJson);

var r = controllers.MyController.createFromJson;
$.ajax({url: r.url, type: r.type, data: obj });

在那些改变之后你应该是好的;您的控制器代码看起来很好如果仍然获得400 Bad Request个回复,请检查jQuery是否正确设置了Content-Type标题 - 您可能需要use the contentType option in the jQuery $.ajax call

在仍有400个错误后进行修改:

我刚刚注意到您在Javascript中使用了JSON.parse - as per this answer您应该使用JSON.stringify将对象转换为jQuery可以发送的内容 - 否则它可能会尝试URLEncode数据和/或将字段作为查询参数发送。

另一个需要注意的是,您发送的JSON是否实际上与您尝试解析它的内容一致。我不确定您是否为此问题提供了简化版本,但看起来您正在尝试解析:

{"name": "joe", "age":20}

使用:

request.body.asOpt[JsArray]

哪个始终会产生None - 你没有给它一个数组。

答案 1 :(得分:0)

Play Framework 2.5 for ReativeMongo中对ajax javascript路由的回答:

routes.conf:

GET     /javascriptRoutes      controllers.HRController.javascriptRoutes

HRController:

def javascriptRoutes = Action { implicit request =>
Ok(
  JavaScriptReverseRouter("jsRoutes")(
    routes.javascript.HRController.createBulkFromAjax
  )
).as("text/javascript")

}

routes.conf:

POST    /heartrates/add     controllers.HRController.createBulkFromAjax

main.scala.html:

<script type="text/javascript" src="@routes.HRController.javascriptRoutes"></script>

的javascript:

var r = jsRoutes.controllers.HRController.createBulkFromAjax();
$.ajax({url: r.url, type: r.type, contentType: "application/json", data: JsonString });

HRController:

def createBulkFromAjax = Action.async(parse.json) { request =>
//Transformation silent in case of failures.
val documents = for {
  heartRate        <- request.body.asOpt[JsArray].toStream
  maybeHeartRate   <- heartRate.value
  validHeartRate   <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate

for {
  heartRate <- hrFuture
  multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
  Logger.debug(s"Successfully inserted with multiResult: $multiResult")
  Created(s"Created ${multiResult.n} heartRate")
}
}

HRController.createBulkFromAjax是从Lightbend激活器ui种子示例构建的,名为play.ReactiveMogno