使用 Akka HTTP(正式名称为 Spray)查询 GET 请求的参数
Query parameters for GET requests using Akka HTTP (formally known as Spray)
Akka HTTP(正式名称为 Spray)的一个特性是它能够自动将数据从 json 来回编组和解组到 case classes 等。我已经成功地让它运行良好。
目前,我正在尝试制作一个 HTTP 客户端,它使用查询参数执行 GET 请求。目前的代码如下所示:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/""" +
s"query?seq=${seq}" +
s"&max-mismatches=${maxMismatches}" +
s"&pam-policy=${pamPolicy}"))
嗯,这不是很漂亮。如果我可以只传递一个包含查询参数的案例 class,并让 Akka HTTP 自动生成查询参数,就像它为 json 所做的那样,那就太好了。 (此外,Akka HTTP 的服务器端有一种解析 GET 查询参数的优雅方式,因此人们会认为它也有一种优雅的方式来生成它们。)
我想做如下事情:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/query""",
entity = QueryParams(seq = seq, maxMismatches = maxMismatches, pamPolicy = pamPolicy)))
只是,上面的方法实际上行不通
我想用 Akka HTTP 以某种方式实现吗?还是我只需要以老式的方式做事?即,显式生成查询参数,就像我在上面的第一个代码块中所做的那样。
(我知道,如果我将其从 GET 更改为 POST,我可能会让它更像我希望的那样工作,从那以后我可以获得内容的 POST 请求自动从大小写 class 转换为 json,但我真的不想在这里这样做。)
显然这可以通过改变 Akka HTTP 的扩展能力来完成,但是对于你需要的(只是一种构建查询字符串的更简洁的方法),你可以用一些 scala 的乐趣来完成:
type QueryParams = Map[String, String]
object QueryParams {
def apply(tuples: (String, String)*): QueryParams = Map(tuples:_*)
}
implicit class QueryParamExtensions(q: QueryParams) {
def toQueryString = "?"+q.map{
case (key,value) => s"$key=$value" //Need to do URL escaping here?
}.mkString("&")
}
implicit class StringQueryExtensions(url: String) {
def withParams(q: QueryParams) =
url + q.toQueryString
}
val params = QueryParams(
"abc" -> "def",
"xyz" -> "qrs"
)
params.toQueryString // gives ?abc=def&xyz=qrs
"http://www.google.com".withParams(params) // gives http://www.google.com?abc=def&xyz=qrs
您可以利用 Uri
class 来做您想做的事。它提供了多种方法来使用 withQuery
方法将一组参数放入查询字符串中。例如,您可以这样做:
val params = Map("foo" -> "bar", "hello" -> "world")
HttpRequest(Uri(hostAndPath).withQuery(params))
或者
HttpRequest(Uri(hostAndPath).withQuery(("foo" -> "bar"), ("hello" -> "world")))
Akka HTTP(正式名称为 Spray)的一个特性是它能够自动将数据从 json 来回编组和解组到 case classes 等。我已经成功地让它运行良好。
目前,我正在尝试制作一个 HTTP 客户端,它使用查询参数执行 GET 请求。目前的代码如下所示:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/""" +
s"query?seq=${seq}" +
s"&max-mismatches=${maxMismatches}" +
s"&pam-policy=${pamPolicy}"))
嗯,这不是很漂亮。如果我可以只传递一个包含查询参数的案例 class,并让 Akka HTTP 自动生成查询参数,就像它为 json 所做的那样,那就太好了。 (此外,Akka HTTP 的服务器端有一种解析 GET 查询参数的优雅方式,因此人们会认为它也有一种优雅的方式来生成它们。)
我想做如下事情:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/query""",
entity = QueryParams(seq = seq, maxMismatches = maxMismatches, pamPolicy = pamPolicy)))
只是,上面的方法实际上行不通
我想用 Akka HTTP 以某种方式实现吗?还是我只需要以老式的方式做事?即,显式生成查询参数,就像我在上面的第一个代码块中所做的那样。
(我知道,如果我将其从 GET 更改为 POST,我可能会让它更像我希望的那样工作,从那以后我可以获得内容的 POST 请求自动从大小写 class 转换为 json,但我真的不想在这里这样做。)
显然这可以通过改变 Akka HTTP 的扩展能力来完成,但是对于你需要的(只是一种构建查询字符串的更简洁的方法),你可以用一些 scala 的乐趣来完成:
type QueryParams = Map[String, String]
object QueryParams {
def apply(tuples: (String, String)*): QueryParams = Map(tuples:_*)
}
implicit class QueryParamExtensions(q: QueryParams) {
def toQueryString = "?"+q.map{
case (key,value) => s"$key=$value" //Need to do URL escaping here?
}.mkString("&")
}
implicit class StringQueryExtensions(url: String) {
def withParams(q: QueryParams) =
url + q.toQueryString
}
val params = QueryParams(
"abc" -> "def",
"xyz" -> "qrs"
)
params.toQueryString // gives ?abc=def&xyz=qrs
"http://www.google.com".withParams(params) // gives http://www.google.com?abc=def&xyz=qrs
您可以利用 Uri
class 来做您想做的事。它提供了多种方法来使用 withQuery
方法将一组参数放入查询字符串中。例如,您可以这样做:
val params = Map("foo" -> "bar", "hello" -> "world")
HttpRequest(Uri(hostAndPath).withQuery(params))
或者
HttpRequest(Uri(hostAndPath).withQuery(("foo" -> "bar"), ("hello" -> "world")))