AkkaHttp - Создание клиента внутри сервера - PullRequest
0 голосов
/ 20 мая 2018

Я создал клиент Akka-Http внутри сервера, который получает GET-запрос от браузера, а затем использует один его параметр для отправки POST-запроса в Twitter.Затем сервер делает строку JSON из ответа Twitter и возвращает ее браузеру.

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 и редактирую JsonRSP с информацией, предоставленной Twitter.Во второй раз, когда я вызываю этот API-интерфейс StepOne, строка JsonRSP не редактируется и снова печатает «нулевую строку».Это происходит несмотря на то, что Twitter каждый раз дает мне правильную информацию.

Так, например, в первый раз я получаю:

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

Но во второй раз, когда я вызываю мой API, он возвращает:

"Null String"

Есть идеи?Я хорошо известен своими очевидными ошибками, поэтому, пожалуйста, помогите мне!

________ РЕДАКТИРОВАТЬ ______

Я отредактировал код, чтобы избавиться от вспомогательной переменной, которая вообще не нужна.Поэтому главное здесь - если я печатаю jsonRSP внутри de runForeach, он печатает правильный JSON.Но когда я печатаю его перед выполнением полного, он снова печатает «нулевую строку».Чтобы сделать его более странным, он по-прежнему завершает правильный JSON в первый раз, но "нулевая строка" во второй раз.Так что я понятия не имею, почему это происходит.Если мой код не работает, он не должен работать каждый раз, так почему он работает в первый раз?

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

Наконец я выбрал то, что чище.Благодаря ответу @ 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 для его анализа и работы с ним.

Так намного чище.

0 голосов
/ 20 мая 2018

Я думаю, что ваша проблема связана с Future, потому что вы на самом деле не ждете ответа, complete(HttpEntity(ContentTypes.'application/json', jsonRSP)), вы всегда возвращаете jsonRSP.Вам следует дождаться вычисления Future и затем вернуть его.

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