捕获由withSizeLimit指令抛出的EntityStreamSizeException。

huangapple go评论102阅读模式
英文:

How to catch EntityStreamSizeException thrown by withSizeLimit Directive

问题

我已创建了一个在akka http中用于上传文件的POST请求。

以下是我的代码:

final val MEDIA_FILE_UPLOAD_MAX_SIZE = 30 * 1024 * 1024

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
      parameter(Symbol("location_id").as[String]) {
        locationId =>
          withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
            withRequestTimeout(120.seconds) {
              entity(as[Multipart.FormData]) {
                formData =>
                  val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
                  // 提取文件部分并开始上传过程
              }
            }
          }
      }
    }
}

如果我使用大于30MB的文件,我在Postman中会得到一个400 BadRequest的错误,消息如下:

EntityStreamSizeException: incoming entity size (47350868) exceeded size limit (31457280 bytes)! This may have been a parser limit (set via akka.http.[server|client].parsing.max-content-length), a decoder limit (set via akka.http.routing.decode-max-size), or a custom limit set with withSizeLimit.

我尝试了以下两种方法:

a) 使用handleException指令:

val customExceptionHandler: ExceptionHandler = ExceptionHandler {
  case _: EntityStreamSizeException =>
    complete(StatusCodes.PayloadTooLarge, "文件大小超过了30MB的限制")
}

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
      handleException(customExceptionHandler) {
        parameter(Symbol("location_id").as[String]) {
          locationId =>
            withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
              withRequestTimeout(120.seconds) {
                entity(as[Multipart.FormData]) {
                  formData =>
                    val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
                    // 提取文件部分并开始上传过程
                }
              }
            }
        }
      }
    }
}

b) 使用handleRejection指令:

val customRejectionHandler: RejectionHandler = RejectionHandler.newBuilder()
  .handle {
    case EntityStreamSizeException(limit, actualSize) =>
      complete(StatusCodes.PayloadTooLarge, s"文件大小超过了${limit}字节的限制")
  }
  .result()

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
      handleRejection(customRejectionHandler) {
        parameter(Symbol("location_id").as[String]) {
          locationId =>
            withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
              withRequestTimeout(120.seconds) {
                entity(as[Multipart.FormData]) {
                  formData =>
                    val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
                    // 提取文件部分并开始上传过程
                }
              }
            }
        }
      }
    }
}

但是这两种方法都不起作用。请问如何捕获此异常并提供自定义消息?

英文:

I have created a post request in akka http to upload a file

Here is my code

final val MEDIA_FILE_UPLOAD_MAX_SIZE = 30 * 1024 * 1024

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
      parameter(Symbol("location_id").as[String]) {
        locationId =>
          withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
            withRequestTimeout(120.seconds) {
              entity(as[Multipart.FormData]) {
                formData =>
                  val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
                  // extract file parts and start the upload process
              }
            }
          }
      }
    }
}

If I use a file greater than 30MB I get a 400 BadRequest in postman with following message

> EntityStreamSizeException: incoming entity size (47350868) exceeded size limit (31457280 bytes)! This may have been a parser limit (set via akka.http.[server|client].parsing.max-content-length), a decoder limit (set via akka.http.routing.decode-max-size), or a custom limit set with withSizeLimit.

I have tried following approach
a) using handleException directive

 val customExceptionHandler: ExceptionHandler = ExceptionHandler {
    case _: EntityStreamSizeException =>
      complete(StatusCodes.PayloadTooLarge, "File size exceeded the limit of 30MB")
  }

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
    	handleException(customExceptionHandler) {
    		parameter(Symbol("location_id").as[String]) {
	        locationId =>
	          withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
	            withRequestTimeout(120.seconds) {
	              entity(as[Multipart.FormData]) {
	                formData =>
	                  val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
	                  // extract file parts and start the upload process
	              }
	            }
	          }
	      }
    	}
    }
}

b) using handleRejection directive

val customRejectionHandler: RejectionHandler = RejectionHandler.newBuilder()
    .handle {
      case EntityStreamSizeException(limit, actualSize) =>
        complete(StatusCodes.PayloadTooLarge, s"File size exceeded the limit of ${limit} bytes")
    }
    .result()

def uploadMediaObjectForASite(): Route = path("Some path") {
  userId =>
    post {
    	handleRejection(customRejectionHandler) {
    		parameter(Symbol("location_id").as[String]) {
	        locationId =>
	          withSizeLimit(MEDIA_FILE_UPLOAD_MAX_SIZE) {
	            withRequestTimeout(120.seconds) {
	              entity(as[Multipart.FormData]) {
	                formData =>
	                  val metadataList = List(TITLE, DESCRIPTION, UPLOADED_BY)
	                  // extract file parts and start the upload process
	              }
	            }
	          }
	      }
    	}
    }
}

But none of them works

How can I catch this exception and provide custom message.

答案1

得分: 0

You may use the directives handleExceptions()/handleRejections() like this:

  val handleErrors = handleExceptions(customExceptionHandler) & handleRejections(customRejectionHandler)

  val routes: Route = {
    handleErrors {
      concat(uploadMediaObjectForASite, myOtherRoute)
    }
  }

Also see this working example. Not sure why your approach is not working though, although I just see the handleExceptions directive in 10.5.2 (and not handleException). Also, I see that the response PayloadTooLarge is deprecated in favor of ContentTooLarge.

英文:

You may use the directives handleExceptions()/handleRejections() like this:

  val handleErrors = handleExceptions(customExceptionHandler) &  handleRejections(customRejectionHandler)

  val routes: Route = {
    handleErrors {
      concat(uploadMediaObjectForASite, myOtherRoute)
    }
  }

Also see this working example. Not sure why your approach is not working though, although I just see the handleExceptionsdirective in 10.5.2 (and not handleException). Also I see that the response PayloadTooLarge is deprecated in favour of ContentTooLarge.

huangapple
  • 本文由 发表于 2023年8月11日 02:25:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76878414.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定