代码之家  ›  专栏  ›  技术社区  ›  franpen

Akkahtp-在服务器中创建客户端

  •  1
  • franpen  · 技术社区  · 7 年前

    我在服务器中构建了一个Akka Http客户端,它通过浏览器获取GET请求,然后使用它的一个参数向Twitter发出POST请求。然后,服务器从Twitter的响应中生成一个JSON字符串,并将其返回给浏览器。

    This image describes this simple interaction

    所以,我的代码有效。是的。问题是它只能工作一次。如果我再次调用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-]+)", "\"$1\"") + "}"
                   // 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的变量,它最初打印“空字符串”。之后,我打了一个POST电话,用Twitter提供的信息编辑JsonRSP。第二次调用这个StepOne API时,JsonRSP字符串没有被编辑,它会再次打印“空字符串”。尽管Twitter每次都给我正确的信息,但这种情况还是发生了。

    例如,我第一次得到:

    {"oauth_token":"mytoken","oauth_token_secret":"mysecrettoken","oauth_callback_confirmed":"true"}
    

    但第二次调用API时,它返回:

    “空字符串”

    有什么想法吗?我以犯明显的错误而闻名,所以请帮帮我!

    ________编辑______

    我编辑了代码,去掉了一个根本不需要的aux变量。 这里的主要问题是,如果我在de runForeach中打印jsonRSP,它会打印正确的JSON。但当我在完成之前打印它时,它会再次打印“空字符串”。更奇怪的是,它第一次仍然完成了正确的json,但第二次完成了“空字符串”。所以我不知道为什么会这样。如果我的代码不应该工作,它不应该每次都工作,那么为什么它第一次工作呢?

    2 回复  |  直到 7 年前
        1
  •  1
  •   earlymorningtea    7 年前

    我认为你的问题与 Future ,因为你实际上并不等待回复, complete(HttpEntity(ContentTypes.'application/json', jsonRSP)) 你总是回来 jsonRSP .你应该等 将来 计算,然后返回。

    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-]+)", "\"$1\"") + "}"
                    })
                    }
                    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))
            })
            }
        }
    }
    
        2
  •  1
  •   franpen    7 年前

    最后我选择了更干净的。多亏@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字符串来解析它并使用它。

    这样更干净。