【问题标题】:Return JSON errors in akka-http API在 akka-http API 中返回 JSON 错误
【发布时间】:2016-02-03 19:18:56
【问题描述】:

在我正在编写的 API 中,我想获取并返回 JSON,即使在出现错误的情况下也是如此。我试图弄清楚如何保留所有 default RejectionHandler 行为,但将状态代码和文本转换为 JSON 对象。由于默认行为是在函数调用中指定的,而不是作为数据结构,似乎唯一的方法是转换它产生的结果的HttpEntity。有没有简单的方法来做到这一点?

【问题讨论】:

    标签: scala akka-http


    【解决方案1】:

    你可以在你的HttpService写这样的东西

    private val defaultRejectionHandler = RejectionHandler.default
    
    implicit def myRejectionHandler =
      RejectionHandler.newBuilder()
        .handleAll[Rejection] { rejections ⇒
    
        def prefixEntity(entity: ResponseEntity): ResponseEntity = entity match {
          case HttpEntity.Strict(contentType, data) => {
            import spray.json._
            val text = ErrorResponse(0, "Rejection", data.utf8String).toJson.prettyPrint
            HttpEntity(ContentTypes.`application/json`, text)
          }
          case _ =>
            throw new IllegalStateException("Unexpected entity type")
        }
    
        mapResponseEntity(prefixEntity) {
          defaultRejectionHandler(rejections).getOrElse {
            complete(StatusCodes.InternalServerError)
          }
        }
      }.handleNotFound {
        complete(StatusCodes.Forbidden -> ErrorResponse(StatusCodes.NotFound.intValue, "NotFound", "Requested resource is not found"))
      }.result()
    

    ErrorResponse 可能在哪里

    case class ErrorResponse(error: ErrorInfo)
    case class ErrorInfo(code: Int, `type`: String, message: String)
    

    您可以为其定义 json marshallers。

    【讨论】:

    • 该死,这很复杂。和我现在解决它的方式一样复杂。 API 中似乎缺少一些东西,没有更简单的方法。
    • 如果您找到更简单的方法,请告诉我:)
    【解决方案2】:

    我拼凑了我自己的版本,但它有一些我不喜欢的粗糙边缘。 ruslan's answer 给了我一些改进的想法。以下是我想出的,综合了这两种方法的优点:

    /**
      * Modifies the Akka-Http default rejection handler to wrap the default
      * message in JSON wrapper, preserving the original status code.
      *
      * @param rejectionWrapper wraps the message in a structure to format the
      *                         resulting JSON object
      * @param writer writer for the wrapper type
      * @tparam WrapperType type of the wrapper
      * @return the modified rejection handler
      */
    def defaultRejectionHandlerAsJson[WrapperType](rejectionWrapper: String => WrapperType)(implicit writer: JsonWriter[WrapperType]) = {
      def rejectionModifier(originalMessage: String): String = {
        writer.write(rejectionWrapper(originalMessage)).prettyPrint
      }
      modifiedDefaultRejectionHandler(rejectionModifier, ContentTypes.`application/json`)
    }
    
    /**
      * Modifies the Akka-Http default rejection handler, converting the default
      * message to some other textual representation.
      *
      * @param rejectionModifier the modifier function
      * @param newContentType the new Content Type, defaulting to text/plain
      *                       UTF-8
      * @return the modified rejection handler
      */
    def modifiedDefaultRejectionHandler(rejectionModifier: String => String, newContentType: ContentType.NonBinary = ContentTypes.`text/plain(UTF-8)`) = new RejectionHandler {
      def repackageRouteResult(entity: ResponseEntity): ResponseEntity = entity match {
        // If the entity isn't Strict (and it definitely will be), don't bother
        // converting, just throw an error, because something's weird.
        case strictEntity: HttpEntity.Strict =>
          val modifiedMessage = rejectionModifier(strictEntity.data.utf8String)
          HttpEntity(newContentType, modifiedMessage)
        case other =>
          throw new Exception("Unexpected entity type")
      }
    
      def apply(v1: Seq[Rejection]): Option[Route] = {
        // The default rejection handler should handle all possible rejections,
        // so if this isn't the case, return a 503.
        val originalResult = RejectionHandler.default(v1).getOrElse(complete(StatusCodes.InternalServerError))
        Some(mapResponseEntity(repackageRouteResult) {
          originalResult
        })
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 2018-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-01
      相关资源
      最近更新 更多