【问题标题】:Kotlin & Spring MVC - HTTP Status 400 - NullKotlin 和 Spring MVC - HTTP 状态 400 - Null
【发布时间】:2021-01-01 15:11:13
【问题描述】:

我有一个 Kotlin @RestController,我希望它在 null 被传递给 @RequestParam 参数的情况下返回 400错误请求

示例:

@RestController
class Api() {

  @PostMapping("endpoint")
  fun endpoint(@DateTimeFormat(iso = DATE) @RequestParam date: LocalDate) {
    //do something
  }
}

如果我向 POST /endpoint?date 发出请求,我会收到 500 Internal Server Error,其中包含以下(缩短的)正文:

{
  "timestamp": "2020-09-14T20:39:38.102+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "Parameter specified as non-null is null: method Api.endpoint, parameter date",
  "trace": "java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Api.endpoint, parameter date\r\n\tat Api.endpoint(Api.kt)\r\n\t 
    ...
    ...
    atjava.base/java.lang.Thread.run(Thread.java:834)\r\n",
 "path": "/campaigns/contributions/unfunded/retries"
}

有没有什么办法可以使用一些额外的库、配置或一些没有其他副作用的自定义代码来解决这个问题

【问题讨论】:

    标签: spring spring-boot kotlin


    【解决方案1】:

    以下适用于 Kotlin 1.4.*。这不一定是最佳答案,因为无法保证 Kotlin 在未来版本中不会更改消息的 excption 类型。例如,当我最初问我使用 1.3.* 的问题时,例外是 IllegalArgumentException。在 1.4.* 中它已更改为 NullPointerException。

    @ControllerAdvice
    class KotlinNonNullParamHandling {
    
        @ExceptionHandler
        protected fun handleKotlinNonNullViolation(
            exception: NullPointerException,
            response: HttpServletResponse
        ) {
            val nullParameter = exception.message?.startsWith("Parameter specified as non-null is null: ") == true
            val restController = exception
                .stackTrace
                .getOrNull(0)
                ?.let { Class.forName(it.className) }
                ?.getAnnotation(RestController::class.java) != null
            val status =
                if (nullParameter && restController) HttpStatus.BAD_REQUEST
                else HttpStatus.INTERNAL_SERVER_ERROR
            response.sendError(status.value(), exception.message)
        }
    }
    

    在假设它是 400 之前,我们正在检查异常

    • NullPointerException
    • 有一条以“指定为非空的参数为空:”开头的消息
    • 它是从一个是 RestController 的类中抛出的(否则可能是其他一些问题,例如通过反射将 null 发送到与 Web 层无关的方法。)

    【讨论】:

      【解决方案2】:

      当验证失败时,Spring 默认会抛出 IllegalArgumentException。默认情况下,Spring-Boot 应用程序中的每个异常都将被视为 InternalServerError。 您可以通过添加如下函数来修改响应代码:

      @RestController
      class Api() {
      
        @ExceptionHandler(IllegalArgumentException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public void onIllegalArgumentException(IllegalArgumentException e) {
        }
      
        @PostMapping("endpoint")
        fun endpoint(@DateTimeFormat(iso = DATE) @RequestParam date: LocalDate) {
          //do something
        }
      }
      
      

      之后,您将在无效请求参数上获得 400 状态代码。

      【讨论】:

        【解决方案3】:

        我已经测试了您的代码,没有明显的问题 - 可以正常工作。

        curl -v -d "date=2020-10-01" http://localhost:8080/endpoint
        *   Trying ::1:8080...
        * TCP_NODELAY set
        * Connected to localhost (::1) port 8080 (#0)
        > POST /endpoint HTTP/1.1
        > Host: localhost:8080
        > User-Agent: curl/7.68.0
        > Accept: */*
        > Content-Length: 15
        > Content-Type: application/x-www-form-urlencoded
        > 
        * upload completely sent off: 15 out of 15 bytes
        * Mark bundle as not supporting multiuse
        < HTTP/1.1 200 
        < Content-Length: 0
        < Date: Tue, 13 Oct 2020 07:04:21 GMT
        < 
        * Connection #0 to host localhost left intact
        

        所以我会:

        1. 验证客户端是否正确格式化请求 - 例如尝试将 Content-Type 标头显式设置为 application/x-www-form-urlencoded,检查参数名称等是否没有拼写错误。
        2. 您已正确配置 Jackson 以使用 Kotlin(com.fasterxml.jackson.module:jackson-module-kotlin - 依赖项)

        【讨论】:

        • 我的问题是查看日期为空的情况,这会导致 Kotlin 抛出异常。这会导致 500 错误,但在这种情况下 400 会更合适。
        • 哦,我看错了你的问题,很抱歉。我会更新答案。
        • @joseph-k-strauss,你试过 StefanD 回答吗?
        • 该答案将返回 400,即使是合法的 500 错误,即抛出 IllegalArgumentException 的其他原因。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-24
        • 2017-12-20
        • 2016-04-20
        • 2020-10-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多