Akka-http:接受和内容类型处理

时间:2015-08-24 17:07:51

标签: scala akka akka-http

我正在尝试Akka-http,希望有人可以解释以下问题:

  1. 如何根据请求中的accept:标头创建不同的路由?例如,我想要一个代码路径来处理“json”,一个处理“xml”请求(如果缺少标题,默认为“json”)

  2. 如果我不希望推断出contentType,我该如何指定它?例如,在下面的代码中,我尝试通过compactPrint()运行json,但这会将其更改为字符串,因此为“text / plain”。我想覆盖它并告诉客户端它仍然是json。

  3. 我的代码是这样的;

    ...
    path("api") {
              get {
                  complete {
                    getStuff.map[ToResponseMarshallable] {
                      case Right(r) if r.isEmpty => List[String]().toJson.compactPrint
                      case Right(r) => r.toJson.compactPrint
                      case Left(e) => BadRequest -> e
                    }
                  }
              }
            }
    ...
    

    这种情况下的响应是text / plain,因为compactPrint创建了一个字符串。 批评非常欢迎。 ;)

2 个答案:

答案 0 :(得分:1)

问题#1的潜在答案似乎是这样,但我想通过自定义指令或更优雅的方式来做到这一点。不幸的是,Akka-Http自定义指令的文档似乎缺失了。

// the encodings I want, in the order of preference
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))

    ...
    path("api") {
              (get & extract(_.request.acceptedMediaRanges)){  
                  r => 
                    val encoding = 
                      r.intersect(myEncodings).headOption
                         .getOrElse(MediaRange(`application/json`))
                  complete {
                         // check "encoding" here and make decision.
                  }
              }
            }
    ...

希望有人能提供更清洁的东西。

答案 1 :(得分:1)

似乎接受的答案不再适用于akka-http v10.0.3。

但这有效:

// the encodings I want, in the order of preference
val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))

...
path("api") {
          (get & extract(_.request.headers)){ requestHeaders =>
              val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders)
              val encoding = mediaTypeNegotiator
                     .acceptedMediaRanges
                     .intersect(myEncodings)
                     .headOption
                     .getOrElse(MediaRange(`application/json`))
              complete {
                     // check "encoding" here and make decision.
              }
          }
        }
...

你也可以

val myEncodings = Seq(MediaRange(`application/xml`),MediaRange( `application/json`))

path("api") {
      (get & extract(_.request.headers)){ requestHeaders =>
        complete {
          val mediaTypeNegotiator = new MediaTypeNegotiator(requestHeaders)
          if(mediaTypeNegotiator.accept(MediaTypes.`application/xml`)) {
            // respond with xml
          } else if(mediaTypeNegotiator.accept(MediaTypes.`application/json`)) {
            // respond with json
          } else {
            // respond with json by default or reject properly :
            reject(UnsupportedRequestContentTypeRejection(Set(MediaTypes.`application/xml`, MediaTypes.`application/json`)))
          }
      }
    }
}

希望这会有所帮助。