5

我想使用 Akka Http 路由系统及其拒绝系统,但需要将响应 Json 嵌套在通用 Json 消息块中以进行拒绝。

我以一种非常非通用的方式工作,创建一个 RejectionHandler 然后为所有可能的拒绝添加案例,并使用特定的响应代码和消息处理它们。

例子:

    // Wraps string into control block format
def WrappingBlock(msg: String) = ???

val myRejectionHandler = RejectionHandler
.newBuilder()
.handle{case MalformedRequestContentRejection(msg, detail) =>
          complete(BadRequest, WrappingBlock(msg)) }
...     // Further lines for all other possible rejections
...     // along with their response codes and messages.
...     // It would be nice if this was just generic code 
...     // rather than specific to every rejection type.
.result()


val routes = handleRejections(myRejectionHandler){ 
    ...
}

但是,我想要的是 Akka HTTP 默认提供的响应代码以及提供的漂亮打印消息,它只是嵌套在 Json 控件包装器中,没有针对每种可能的拒绝类型的行。这似乎应该是可能的,但我无法完成它。

4

1 回答 1

5

我认为可以使用handleRejections显式与mapResponse. 首先,考虑这个简单的路由定义:

(get & path("foo")){
  complete((StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, """{"foo": "bar"}""" )))
}

如果我收到匹配的请求,我将使用 json 进行响应,我的调用者很高兴,因为他们可以将响应解析为 json。但是,如果您尝试使用 POST 请求调用此端点,您将收到如下响应:

HTTP 405 Method Not Allowed

Date: Wed, 06 Jan 2016 13:19:27 GMT
Content-Type: text/plain; charset=UTF-8
Content-Length: 47
Allow: GET
Server: akka-http/2.3.12

HTTP method not allowed, supported methods: GET

所以在这里我们得到了一个不可取的纯文本响应。我们可以通过在路由树的最顶部添加几个指令来普遍解决这个问题,如下所示:

mapResponse(wrapToJson){
  handleRejections(RejectionHandler.default){
    (get & path("foo")){
      complete((StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, """{"foo": "bar"}""" )))
    }
  }
}

wrapToJson定义为:

def wrapToJson(resp:HttpResponse):HttpResponse = {

  //If we get a text/plain response entity, remap it otherwise do nothing
  val newResp = resp.entity match{
    case HttpEntity.Strict(ContentTypes.`text/plain(UTF-8)` , content ) => 
      val jsonResp = s"""{"error": "${content.utf8String}"}"""
      resp.copy(entity = HttpEntity(ContentTypes.`application/json`, jsonResp))
    case other =>
      resp
  }

  newResp
}

This is a very basic example, and you'd probable have a better way to generating the json, but this just serves to show how you can fix the plan text responses from the default rejection handler. Now, you must nest the default rejection handler under the mapResponse explicitly because the automatic handling gets added outside the top level of whatever tree you define and thus mapResponse would not see the rejection cases. You still get the default handling though via RejectionHandler.default.

Hopefully this is close to what you were after.

于 2016-01-06T13:26:24.437 回答