AkkaHttp - 在服务器中创建客户端
AkkaHttp - Making a Client inside a Server
我在服务器中构建了一个 Akka-Http 客户端,它通过浏览器获取 GET 请求,然后使用它的一个参数向 Twitter 发出 POST 请求。然后,服务器从 Twitter 的响应中生成一个 JSON 字符串并将其返回给浏览器。
所以,我的代码有效。确实如此。问题是它只能工作一次。如果我第二次调用 GET /StepOne,它会失败。
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
var response: String = null
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
var jsonRSP = "null string"
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
responseFuture
.onComplete {
case Success(res) => {
val response = res._3.dataBytes.map(_.utf8String).runForeach(body => {
/* We postedit the string to make it JSON Parsable */
jsonRSP = "{" + body.replaceAll("=", ":")
.replaceAll("&", ",")
.replaceAll("([\w-]+)", "\"\"") + "}"
// jsonRSP = postBody
println(jsonRSP)
})
}
case Failure(_) => sys.error("Couldn't get into api.twitter")
}
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
Await.result(responseFuture, timeout.duration)
println(jsonRSP)
complete(HttpEntity(ContentTypes.`application/json`, jsonRSP))
})
}
}
}
如您所见,我声明了一个名为 JsonRSP 的变量,它最初打印 "null string"。之后,我进行 POST 调用,并使用 Twitter 提供的信息编辑 JsonRSP。我第二次调用此 StepOne API 时,JsonRSP 字符串未被编辑,它再次打印 "null string"。尽管 Twitter 每次都给我正确的信息,但还是会发生这种情况。
所以,例如,我第一次得到:
{"oauth_token":"mytoken","oauth_token_secret":"mysecrettoken","oauth_callback_confirmed":"true"}
但我第二次称我的 API 它 returns:
"Null String"
有什么想法吗?我因犯明显的错误而闻名,所以请帮助我!
________ 编辑 ______
我编辑了代码以删除根本不需要的 aux 变量。
所以这里最主要的是,如果我在 de runForeach 中打印 jsonRSP,它会打印正确的 JSON。但是当我在完成之前打印它时,它会重新打印 "null string" 。更奇怪的是,它第一次仍然完成了正确的 json,但第二次完成了 "null string"。所以我不知道为什么会这样。如果我的代码不应该工作,它不应该每次都工作,那么为什么它第一次工作?
我认为你的问题与 Future
有关,因为你实际上不等待响应,complete(HttpEntity(ContentTypes.'application/json', jsonRSP))
,你总是 return jsonRSP
。您应该等待 Future
计算然后 return 它。
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
var response: String = null
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
responseFuture
.onComplete {
case Success(res) => {
res._3.dataBytes.map(_.utf8String).runForeach(body => {
/* We postedit the string to make it JSON Parsable */
"{" + body.replaceAll("=", ":")
.replaceAll("&", ",")
.replaceAll("([\w-]+)", "\"\"") + "}"
})
}
case Failure(_) => sys.error("Couldn't get into api.twitter")
}
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
val result = Await.result(responseFuture, timeout.duration)
complete(HttpEntity(ContentTypes.`application/json`, result))
})
}
}
}
最后我选择了更干净的。感谢@tea-adict 的回复,我想出了这段代码。
val settings = CorsSettings.defaultSettings.withAllowCredentials(false)
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
try {
val result = Await.result(responseFuture, timeout.duration)
complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`,result.entity.dataBytes))
}
catch{
case e: TimeoutException => complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`,"oauth_token=null&oauth_token_secret=null&callback_confirmed=false"))
}
})
}
}
}
它没有完成 JSON 字符串。相反,它将从 Twitter 获得的相同纯文本发送回前端应用程序。然后,我将在我的前端简单地获取该响应并将其转换为 JSON 字符串以对其进行解析和使用。
这样就干净多了。
我在服务器中构建了一个 Akka-Http 客户端,它通过浏览器获取 GET 请求,然后使用它的一个参数向 Twitter 发出 POST 请求。然后,服务器从 Twitter 的响应中生成一个 JSON 字符串并将其返回给浏览器。
所以,我的代码有效。确实如此。问题是它只能工作一次。如果我第二次调用 GET /StepOne,它会失败。
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
var response: String = null
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
var jsonRSP = "null string"
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
responseFuture
.onComplete {
case Success(res) => {
val response = res._3.dataBytes.map(_.utf8String).runForeach(body => {
/* We postedit the string to make it JSON Parsable */
jsonRSP = "{" + body.replaceAll("=", ":")
.replaceAll("&", ",")
.replaceAll("([\w-]+)", "\"\"") + "}"
// jsonRSP = postBody
println(jsonRSP)
})
}
case Failure(_) => sys.error("Couldn't get into api.twitter")
}
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
Await.result(responseFuture, timeout.duration)
println(jsonRSP)
complete(HttpEntity(ContentTypes.`application/json`, jsonRSP))
})
}
}
}
如您所见,我声明了一个名为 JsonRSP 的变量,它最初打印 "null string"。之后,我进行 POST 调用,并使用 Twitter 提供的信息编辑 JsonRSP。我第二次调用此 StepOne API 时,JsonRSP 字符串未被编辑,它再次打印 "null string"。尽管 Twitter 每次都给我正确的信息,但还是会发生这种情况。
所以,例如,我第一次得到:
{"oauth_token":"mytoken","oauth_token_secret":"mysecrettoken","oauth_callback_confirmed":"true"}
但我第二次称我的 API 它 returns:
"Null String"
有什么想法吗?我因犯明显的错误而闻名,所以请帮助我!
________ 编辑 ______
我编辑了代码以删除根本不需要的 aux 变量。 所以这里最主要的是,如果我在 de runForeach 中打印 jsonRSP,它会打印正确的 JSON。但是当我在完成之前打印它时,它会重新打印 "null string" 。更奇怪的是,它第一次仍然完成了正确的 json,但第二次完成了 "null string"。所以我不知道为什么会这样。如果我的代码不应该工作,它不应该每次都工作,那么为什么它第一次工作?
我认为你的问题与 Future
有关,因为你实际上不等待响应,complete(HttpEntity(ContentTypes.'application/json', jsonRSP))
,你总是 return jsonRSP
。您应该等待 Future
计算然后 return 它。
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
var response: String = null
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
responseFuture
.onComplete {
case Success(res) => {
res._3.dataBytes.map(_.utf8String).runForeach(body => {
/* We postedit the string to make it JSON Parsable */
"{" + body.replaceAll("=", ":")
.replaceAll("&", ",")
.replaceAll("([\w-]+)", "\"\"") + "}"
})
}
case Failure(_) => sys.error("Couldn't get into api.twitter")
}
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
val result = Await.result(responseFuture, timeout.duration)
complete(HttpEntity(ContentTypes.`application/json`, result))
})
}
}
}
最后我选择了更干净的。感谢@tea-adict 的回复,我想出了这段代码。
val settings = CorsSettings.defaultSettings.withAllowCredentials(false)
val route = cors(settings){
path("StepOne"){
get {
parameters('callback.as[String])(cb => {
val callback = this.encodeUriComp(cb)
val url = "https://api.twitter.com/oauth/request_token"
this.oauth_timestamp = this.createTimestamp()
this.oauth_nonce = this.randomString(32)
val authorization = headers.RawHeader("Authorization",
"""OAuth oauth_callback="""" + callback +
"""", oauth_consumer_key="""" + this.consumerKey +
"""", oauth_nonce="""" + this.oauth_nonce +
"""", oauth_signature="""" + this.encodeUriComp(this.createSignature()) +
"""", oauth_signature_method="HMAC-SHA1", oauth_timestamp="""" + this.oauth_timestamp +
"""", oauth_version="1.0"""")
val params = ByteString(callback)
val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(HttpMethods.POST, url,
headers = List(authorization),
entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, params)))
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
try {
val result = Await.result(responseFuture, timeout.duration)
complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`,result.entity.dataBytes))
}
catch{
case e: TimeoutException => complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`,"oauth_token=null&oauth_token_secret=null&callback_confirmed=false"))
}
})
}
}
}
它没有完成 JSON 字符串。相反,它将从 Twitter 获得的相同纯文本发送回前端应用程序。然后,我将在我的前端简单地获取该响应并将其转换为 JSON 字符串以对其进行解析和使用。
这样就干净多了。