从Web应用程序的客户端,我遇到了一个服务器端路由,它只是第三方API的包装器。使用 dispatch,我尝试使该服务器端请求返回第三方 API 对客户端 AJAX 调用的确切标头和响应。
当我这样做时:
val req = host("third-pary.api.com, 80)
val post = req.as("user", "pass") / "route" << Map("key" -> "akey", "val" -> "aval")
Http(post > as.String)
我总是看到返回 AJAX 调用的200
响应(有点意料之中)。我已经看到了使用Either
语法,但我实际上更像是一个Any
,因为它只是确切的响应和标头。怎么写呢?
我应该提到我在服务器端使用 Scalatra,所以本地路由是:
post("/route") {
}
编辑:
这是我正在使用的建议 要么匹配示例,但match
语法没有意义 - 我不在乎是否有错误,我只想返回它。另外,我似乎无法使用此方法返回 BODY。
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
}
理想情况下,解决方案返回 斯卡拉特拉ActionResult(responseStatus(status, reason), body, headers)
.
在使用 Dispatch 时获取响应标头实际上非常容易。例如,使用 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
现在,例如:
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)
...
如果您经常这样做,最好将其封装,例如:
val asHeaders = as.Response { response =>
scala.collection.JavaConverters.mapAsScalaMapConverter(
response.getHeaders
).asScala.toMap.mapValues(_.asScala.toList)
}
现在您可以编写以下内容:
val response: Either[Throwable, Map[String, List[String]]] =
Http(url("http://www.google.com") OK asHeaders).either()
而且你有错误检查,漂亮的不可变集合等。
我们需要对 API 的失败请求的响应正文,因此我们想出了这个解决方案:
使用 code
和 body
定义您自己的 ApiHttpError
类(用于正文文本):
case class ApiHttpError(code: Int, body: String)
extends Exception("Unexpected response status: %d".format(code))
定义类似于displatch
源中使用的OkWithBodyHandler
:
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)
}
}
}
现在,在调用可能引发和异常的代码(调用API
)附近,将implicit
覆盖添加到ToupleBuilder
(再次类似于源代码)并在request
上调用OkWithBody
:
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
}
}
从现在开始,获取either
将为您提供[Throwable, String]
(使用as.String)
,Throwable
是我们code
和body
ApiHttpError
。
希望它有帮助。