在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")
}
}
答案 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