Return exact response/header?

时光总嘲笑我的痴心妄想 提交于 2019-12-24 00:55:38

问题


From the client-side of a webapp, I hit a server-side route which is just a wrapper for a third-party API. Using dispatch, I am trying to make that server-side request return the exact header and response of the third-party API to the client-side AJAX call.

When I do this:

val req = host("third-pary.api.com, 80)
val post = req.as("user", "pass") / "route" << Map("key" -> "akey", "val" -> "aval")
Http(post > as.String)

I always see a 200 response returned to the AJAX call (kind of expectedly). I have seen an Either syntax used, but I'm really more of an Any, as it's just the exact response and header. How would this be written?

I should mention I'm using Scalatra on the server-side, so the local route is:

post("/route") {

}

EDIT:

Here is the suggested Either matching example, which I'm playing with, but the match syntax doesn't make sense - I don't care if there is an error, I just want to return it. Also, I can't seem to get the BODY returned with this method.

val asHeaders = as.Response { response =>
  println("BODY: " + response.getResponseBody())
  scala.collection.JavaConverters.mapAsScalaMapConverter(
    response.getHeaders).asScala.toMap.mapValues(_.asScala.toList)
}

val response: Either[Throwable, Map[String, List[String]]] =
  Http(post > asHeaders).either()

response match {
  case Left(wrong) =>
    println("Left: " + wrong.getMessage())
    // return Action with header + body
  case Right(good) =>
    println("Right: " + good)
    // return Action with header + body
}

Ideally, the solutions returns the Scalatra ActionResult(responseStatus(status, reason), body, headers).


回答1:


It's actually very easy to get response headers while using Dispatch. For example with 0.9.4:

import dispatch._
import scala.collection.JavaConverters._

val headers: java.util.Map[String, java.util.List[String]] = Http(
   url("http://www.google.com")
)().getHeaders

And now, for example:

scala> headers.asScala.mapValues(_.asScala).foreach {
     |   case (k, v) => println(k + ": " + v)
     | }
X-Frame-Options: Buffer(SAMEORIGIN)
Transfer-Encoding: Buffer(chunked)
Date: Buffer(Fri, 30 Nov 2012 20:42:45 GMT)
...

If you do this often it's better to encapsulate it, like this, for example:

val asHeaders = as.Response { response =>
  scala.collection.JavaConverters.mapAsScalaMapConverter(
    response.getHeaders
  ).asScala.toMap.mapValues(_.asScala.toList)
}

Now you can write the following:

val response: Either[Throwable, Map[String, List[String]]] =
  Http(url("http://www.google.com") OK asHeaders).either()

And you've got error checking, nice immutable collections, etc.




回答2:


We needed the response body of failed requests to an API, so we came up with this solution:

Define your own ApiHttpError class with code and body (for the body text):

case class ApiHttpError(code: Int, body: String)
  extends Exception("Unexpected response status: %d".format(code))

Define OkWithBodyHandler similar to what is used in the source of displatch:

class OkWithBodyHandler[T](f: Response => T) extends AsyncCompletionHandler[T] {
  def onCompleted(response: Response) = {
    if (response.getStatusCode / 100 == 2) {
      f(response)
    } else {
      throw ApiHttpError(response.getStatusCode, response.getResponseBody)
    }
  }
}

Now, near your call to the code that might throw and exception (calling API), add implicit override to the ToupleBuilder (again similar to the source code) and call OkWithBody on request:

class MyApiService {
  implicit class MyRequestHandlerTupleBuilder(req: Req) {
    def OKWithBody[T](f: Response => T) =
      (req.toRequest, new OkWithBodyHandler(f))
  }

  def callApi(request: Req) = {
    Http(request OKWithBody as.String).either
  }
}

From now on, fetching either will give you the [Throwable, String] (using as.String), and the Throwable is our ApiHttpError with code and body.

Hope it helped.



来源:https://stackoverflow.com/questions/13651153/return-exact-response-header

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!