简体   繁体   English

如何从akka-stream传播到akka-http的错误都被记录下来并正确通知客户端?

[英]How to get error from akka-stream propagate to akka-http to both be logged and notify the client properly?

Right now I am using akka-stream and akka-HTTP to build a file streaming API. 现在我使用akka-streamakka-HTTP来构建文件流API。 As such I am injecting a streaming source into an entity to have data streamed directly to the HTTP client like so: 因此,我将流式源注入实体,以便将数据直接流式传输到HTTP客户端,如下所示:

complete(HttpEntity(ContentTypes.`application/octet-stream`, source))

However, if for some reason the stream fails, the connection gets closed by akka-http without further explanation or logging. 但是,如果由于某种原因流失败,则连接将被akka-http关闭,而无需进一步说明或记录。

I would need 2 things: 我需要两件事:

  • How can I get the exception logs? 我怎样才能获得异常日志?
  • How can I notify my client with a message before closing the connection? 在关闭连接之前,如何通过消息通知我的客户?

Thank you 谢谢

As mentioned in comment HTTP protocol does not allow to signal error to the client side. 正如评论中所提到的,HTTP协议不允许向客户端发出错误信号。

As to logging: For me it boils down to missing proper access log directive in akka http. 关于日志记录:对我来说,它归结为缺少akka http中的正确访问日志指令。

In my current project we have decorator which register onComplete handler for http entity before giving it to akka http for rendering. 在我当前的项目中,我们有装饰器,它为http实体注册onComplete处理程序,然后将其提供给akka http进行渲染。

  private def onResponseStreamEnd(response: HttpResponse)(action: StatusCode => Unit): HttpResponse =
    if (!response.status.allowsEntity() || response.entity.isKnownEmpty()) {
      action(response.status)
      response
    } else {
      val dataBytes =
        onStreamEnd(response.entity) { result =>
          val overallStatusCode =
            result match {
              case Success(_) =>
                response.status

              case Failure(e) =>
                logger.error(e, s"error streaming response [${e.getMessage}]")
                StatusCodes.InternalServerError
            }

          action(overallStatusCode)
        }

      response.withEntity(response.entity.contentLengthOption match {
        case Some(length) => HttpEntity(response.entity.contentType, length, dataBytes)
        case None         => HttpEntity(response.entity.contentType, dataBytes)
      })
    }

  private def onStreamEnd(entity: HttpEntity)(onComplete: Try[Done] ⇒ Unit): Source[ByteString, _] =
    entity.dataBytes.alsoTo { Sink.onComplete(onComplete) }

Usage: 用法:

complete(onResponseStreamEnd(HttpResponse(StatusCodes.OK, HttpEntity(ContentTypes.`application/octet-stream`, source))){ statusCode => .... })

Similar approach but using custom graph stage you can find here 类似的方法,但使用自定义图阶段,你可以在这里找到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM