如何使用 Akka-Http 一般包装拒绝

How to generically wrap a Rejection with Akka-Http

我想使用 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 控件包装器中,没有一行表示每种可能的拒绝类型.这看起来应该是可能的,但我没能完成它。

我认为可以使用 handleRejectionsmapResponse 的明确组合来完成您想要的操作。首先,考虑这个简单的路由定义:

(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
}

这是一个非常基本的示例,您可能有更好的方法来生成 json,但这只是为了说明如何修复来自默认拒绝处理程序的计划文本响应。现在,您必须明确地将默认拒绝处理程序嵌套在 mapResponse 下,因为自动处理会添加到您定义的任何树的顶层之外,因此 mapResponse 不会看到拒绝案例。您仍然可以通过 RejectionHandler.default 获得默认处理。

希望这与您所追求的相近。