【问题标题】:Play Framework 2.5 ajax json route parameter async MongoDBPlay Framework 2.5 ajax json 路由参数 async MongoDB
【发布时间】:2017-02-22 17:55:19
【问题描述】:

在 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)

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

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 控制器代码取自 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")
}
}

【问题讨论】:

  • 你能告诉我们你的控制器代码吗?
  • 添加了 Scala 控制器代码。

标签: json ajax routes playframework-2.5


【解决方案1】:

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

如果您声明了一个非可选参数(就像您对 ajax: String 所做的那样)并且您没有在请求中实际提供它,Play 将返回一个 400 Bad Request

虽然您在概念上 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 - 你没有给它一个数组。

【讨论】:

  • 我根据 Play 文档设置了 jsrouter,所以 javascript 唯一没有抱怨的路由是: var r = jsRoutes.controllers.MyController.createFromJson(); $.ajax({url: r.url, contentType: "application/json", type: r.type, data: JsonObj });如上所述,我已将 contentType 参数添加到 ajax,但仍然得到错误 400,jsrouter 似乎工作正常: POST localhost:9000/person/add 400 (Bad Request) 任何进一步的帮助表示赞赏。谢谢。
  • 嘿嘿,它有效。我正在为这个问题简化我的代码,但事实证明我的问题是我将 json 作为参数传递时 route.conf 中的重复路由。删除了路线,无论是否使用 Json.parse,它都可以使用,因为我在方括号中进行了硬编码。我不知道字符串化。感谢您的帮助@millhouse。我相信我会有更多的问题。
  • 更正,您对 json.parse 的看法是正确的。我已经删除了。它有效。
【解决方案2】:

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

routes.conf:

GET     /javascriptRoutes      controllers.HRController.javascriptRoutes

人力资源控制器:

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 });

人力资源控制器:

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 是从名为 play.ReactiveMogno 的 Lightbend 激活器 ui 种子示例构建的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多