发布 JSON 条没有键值对的消息 Spray
Posting JSON message with no key value pair Spray
这是我尝试 post 网络服务的示例:
Content-Type: application/json
"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
注意这里没有键值对。我正在尝试使用 'pipelining' 到 POST 这个,但我不断收到以下错误:
> test
[info] Compiling 1 Scala source to /home/chris/dev/coinprism-api/target/scala-2.11/classes...
[error] /home/chris/dev/coinprism-api/src/main/scala/com/coinprism/transaction/TransactionBuilder.scala:102: could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[spray.json.JsObject]
[error] pipeline(Post(host + version + sendrawtransaction, msg))
这是我尝试使用的代码:
import TransactionHashFormat._
import DefaultJsonProtocol._
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
val pipeline: HttpRequest => Future[TransactionHash] =
addHeader("Content-Type" , "application/json") ~> sendReceive ~> unmarshal[TransactionHash]
pipeline(Post(host + version + sendrawtransaction, msg))
我做错了什么?
编辑:
我要呼叫的API:
仅仅因为它被花括号括起来并不能使它有效json。如果你想 post invalid json
,Spray 确实会给你一些选择
不能将 Content-Type "application/text" 和 post msg
设为字符串吗?
让我们分解一下:
a) 正如其他人已经评论的那样,这是无效的 JSON 因此它会在运行时失败:
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
b) 你不能使用编组器,因为目前 spray (1.3.2) 只允许 JSON objects 和数组被编组。这是以前的 JSON 规范 (RFC 4627) 的要求,但新的 RFC 7159 取消了此要求。我创建了一个票证以在将来解决此问题 https://github.com/spray/spray/issues/1034。但是,您定位的 API 需要一个 double-quoted JSON 字符串。
c) 这意味着在这种情况下您不能使用编组(即将 Scala 值自动转换为 HTTP 消息)。这不是您需要自己创建消息的特定问题。这样的事情应该有效:
val pipeline = sendReceive
val hash: String = "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
val msg: String = "\"" + hash + "\""
val request = Post(host + version + sendrawtransaction, HttpEntity(ContentTypes.`application/json`, msg))
// run request
pipeline(request) // receive result as Future[HttpResponse]
您需要了解 spray 专门处理 Content-Type header:它不表示为普通 header,但它被建模为 HttpEntity 的一部分。
不幸的是,unmarshal
不起作用,原因与 b) 中解释的相同,因此您需要自己提取值。
你应该可以大致这样做:
def extractJsonStringResult(res: HttpResponse): String = {
// TODO: check status code
import spray.json._
res.entity.asString(HttpCharsets.`UTF-8`).parseJson match {
case JsString(string) => string
case _ => ??? // TODO: fail
}
}
val pipeline = sendReceive ~> extractJsonStringResult
这是我尝试 post 网络服务的示例:
Content-Type: application/json "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
注意这里没有键值对。我正在尝试使用 'pipelining' 到 POST 这个,但我不断收到以下错误:
> test
[info] Compiling 1 Scala source to /home/chris/dev/coinprism-api/target/scala-2.11/classes...
[error] /home/chris/dev/coinprism-api/src/main/scala/com/coinprism/transaction/TransactionBuilder.scala:102: could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[spray.json.JsObject]
[error] pipeline(Post(host + version + sendrawtransaction, msg))
这是我尝试使用的代码:
import TransactionHashFormat._
import DefaultJsonProtocol._
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
val pipeline: HttpRequest => Future[TransactionHash] =
addHeader("Content-Type" , "application/json") ~> sendReceive ~> unmarshal[TransactionHash]
pipeline(Post(host + version + sendrawtransaction, msg))
我做错了什么?
编辑:
我要呼叫的API:
仅仅因为它被花括号括起来并不能使它有效json。如果你想 post invalid json
,Spray 确实会给你一些选择不能将 Content-Type "application/text" 和 post msg
设为字符串吗?
让我们分解一下:
a) 正如其他人已经评论的那样,这是无效的 JSON 因此它会在运行时失败:
val msg = ("""{"0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"}""").asJson.asJsObject
b) 你不能使用编组器,因为目前 spray (1.3.2) 只允许 JSON objects 和数组被编组。这是以前的 JSON 规范 (RFC 4627) 的要求,但新的 RFC 7159 取消了此要求。我创建了一个票证以在将来解决此问题 https://github.com/spray/spray/issues/1034。但是,您定位的 API 需要一个 double-quoted JSON 字符串。
c) 这意味着在这种情况下您不能使用编组(即将 Scala 值自动转换为 HTTP 消息)。这不是您需要自己创建消息的特定问题。这样的事情应该有效:
val pipeline = sendReceive
val hash: String = "0100000001d238c42ec059b8c7747cd51debb4310108f6279d14957472822cf061a660828b000000006b483045022100d326257244e8cb86889509cf5b4717edf273d9e6e643f571c434753059eb01a902204aa761f44e89b55af0e2fa0caef580401a4ba61eebf8bc29020ce23f6fab1ee2012102661ac805eef8015c7c8d617c65ef327c4f2272fd5d9e97456a0d32d3bcf6f563ffffffff0288130000000000001976a91430a5d35558ade668b8829a2a0f60a3f10358327e88ac306f0100000000001976a914760fdb3483204406ddb73a45b20b7c9be61d0a7e88ac00000000"
val msg: String = "\"" + hash + "\""
val request = Post(host + version + sendrawtransaction, HttpEntity(ContentTypes.`application/json`, msg))
// run request
pipeline(request) // receive result as Future[HttpResponse]
您需要了解 spray 专门处理 Content-Type header:它不表示为普通 header,但它被建模为 HttpEntity 的一部分。
不幸的是,unmarshal
不起作用,原因与 b) 中解释的相同,因此您需要自己提取值。
你应该可以大致这样做:
def extractJsonStringResult(res: HttpResponse): String = {
// TODO: check status code
import spray.json._
res.entity.asString(HttpCharsets.`UTF-8`).parseJson match {
case JsString(string) => string
case _ => ??? // TODO: fail
}
}
val pipeline = sendReceive ~> extractJsonStringResult