akka-http: How to set response headers

2019-03-25 17:23发布

问题:

I've a route as follows:

val route = {
    logRequestResult("user-service") {
      pathPrefix("user") {
        get {
          respondWithHeader(RawHeader("Content-Type", "application/json")) {
            parameters("firstName".?, "lastName".?).as(Name) { name =>
              findUserByName(name) match {
                case Left(users) => complete(users)
                case Right(error) => complete(error)
              }
            }
          }
        } ~
          (put & entity(as[User])) { user =>
            complete(Created -> s"Hello ${user.firstName} ${user.lastName}")
          } ~
          (post & entity(as[User])) { user =>
            complete(s"Hello ${user.firstName} ${user.lastName}")
          } ~
          (delete & path(Segment)) { userId =>
            complete(s"Hello $userId")
          }
      }
    }
  }

The content type of my response should always be application/json as I've it set for the get request. However, what I'm getting in my tests is text/plain. How do I set the content type correctly in the response?

On a side note, the akka-http documentation is one of the most worthless piece of garbage I've ever seen. Almost every link to example code is broken and their explanations merely state the obvious. Javadoc has no code example and I couldn't find their codebase on Github so learning from their unit tests is also out of the question.

回答1:

I found this one post that says "In spray/akka-http some headers are treated specially". Apparently, content type is one of those and hence can't be set as in my code above. One has to instead create an HttpEntity with the desired content type and response body. With that knowledge, when I changed the get directive as follows, it worked.

import akka.http.scaladsl.model.HttpEntity
import akka.http.scaladsl.model.MediaTypes.`application/json`

get {
  parameters("firstName".?, "lastName".?).as(Name) { name =>
    findUserByName(name) match {
      case Left(users) => complete(users)
      case Right(error) => complete(error._1, HttpEntity(`application/json`, error._2))
    }
  }
}