当@Controller returns 是反应类型(Mono)时,如何设置@ExceptionHandler 提供的响应的状态代码?
How can the status code for a response provided by a @ExceptionHandler be set when the @Controller returns a reactive type (Mono)?
当@Controller returns 反应类型 (Mono) 时,如何设置 @ExceptionHandler 提供的响应的状态代码?
似乎无法通过返回 ResponseEntity 或使用 @ResponseStatus 注释 @ExceptionHandler 方法。
显示问题的相当小的测试(请注意,响应正文和内容类型已正确验证,而状态代码正常,而应为 INTERNAL_SERVER_ERROR):
class SpringWebMvcWithReactiveResponseTypeExceptionHandlerCheckTest {
@RestController
@RequestMapping("/error-check", produces = ["text/plain;charset=UTF-8"])
class ExceptionHandlerCheckController {
@GetMapping("errorMono")
fun getErrorMono(): Mono<String> {
return Mono.error(Exception())
}
}
@ControllerAdvice
class ErrorHandler : ResponseEntityExceptionHandler() {
@ExceptionHandler(Exception::class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
fun handleException(ex: Exception): ResponseEntity<*> = ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(mapOf("key" to "value"))
}
val mockMvc = MockMvcBuilders
.standaloneSetup(ExceptionHandlerCheckController())
.setControllerAdvice(ErrorHandler())
.build()
@Test
fun `getErrorMono returns HTTP Status OK instead of the one set by an ExceptionHandler`() {
mockMvc.get("/error-check/errorMono")
// .andExpect { status { isInternalServerError() } }
.andExpect { status { isOk() } }
.asyncDispatch()
.andExpect {
content {
contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
json("""
{
"key": "value"
}
""",strict = true
)
}
}
}
}
(build.gradle.kts 显示相关依赖项的摘录):
plugins: {
id("org.springframework.boot") version "2.4.5"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
问题是 .andExpect { status ...
必须在 .asyncDispatch()
之后调用(就像处理内容类型和正文一样)。似乎 http 状态已更新。可能这实际上是异步请求的 http 标准的一部分,但我怀疑这是底层 MockHttpServletResponse 的错误。
当@Controller returns 反应类型 (Mono) 时,如何设置 @ExceptionHandler 提供的响应的状态代码?
似乎无法通过返回 ResponseEntity 或使用 @ResponseStatus 注释 @ExceptionHandler 方法。
显示问题的相当小的测试(请注意,响应正文和内容类型已正确验证,而状态代码正常,而应为 INTERNAL_SERVER_ERROR):
class SpringWebMvcWithReactiveResponseTypeExceptionHandlerCheckTest {
@RestController
@RequestMapping("/error-check", produces = ["text/plain;charset=UTF-8"])
class ExceptionHandlerCheckController {
@GetMapping("errorMono")
fun getErrorMono(): Mono<String> {
return Mono.error(Exception())
}
}
@ControllerAdvice
class ErrorHandler : ResponseEntityExceptionHandler() {
@ExceptionHandler(Exception::class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
fun handleException(ex: Exception): ResponseEntity<*> = ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_PROBLEM_JSON)
.body(mapOf("key" to "value"))
}
val mockMvc = MockMvcBuilders
.standaloneSetup(ExceptionHandlerCheckController())
.setControllerAdvice(ErrorHandler())
.build()
@Test
fun `getErrorMono returns HTTP Status OK instead of the one set by an ExceptionHandler`() {
mockMvc.get("/error-check/errorMono")
// .andExpect { status { isInternalServerError() } }
.andExpect { status { isOk() } }
.asyncDispatch()
.andExpect {
content {
contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
json("""
{
"key": "value"
}
""",strict = true
)
}
}
}
}
(build.gradle.kts 显示相关依赖项的摘录):
plugins: {
id("org.springframework.boot") version "2.4.5"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
问题是 .andExpect { status ...
必须在 .asyncDispatch()
之后调用(就像处理内容类型和正文一样)。似乎 http 状态已更新。可能这实际上是异步请求的 http 标准的一部分,但我怀疑这是底层 MockHttpServletResponse 的错误。