无法验证 Spring Boot/Kotlin 协程控制器中的请求参数
在 SpringBoot/Kotlin 协程项目中,我有一个像这样的控制器类。
@RestContollser
@Validated
class PostController(private val posts: PostRepository) {
suspend fun search(@RequestParam q:String, @RequestParam @Min(0) offset:Int, @RequestParam @Min(1) limit:Int): ResponseEntity<Any> {}
}
@ResquestBody 上的验证与一般的 Spring WebFlux 一样工作,但是在测试
验证请求参数时,它失败并抛出异常,例如:
java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4165)
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
它不是 ConstraintViolationException 。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为当您使用协程时,这是框架中的一个错误(更新,是的,我看到快乐歌曲评论)。总之:
“@Validated 确实还不符合协程标准,我们需要通过使用协程感知方法来发现方法参数来解决这个问题。”
麻烦的是,你的控制器上的方法的签名实际上被Spring增强了,有一个额外的参数,像这样,添加一个延续:
所以当hibernate验证器调用getParameter名称来获取你的方法上的参数列表时,它认为请求中总共有 4 个,然后尝试获取第 4 个(索引 3)时出现索引越界异常。
如果你在 this: 的返回上放置一个断点
,并放置一个断点条件
index ==3 && a.length <4
你可以看到发生了什么。我会将其报告为 Spring 问题跟踪器上的错误。
您可能最好采用另一种方法,如此处所述,使用 RequestBody 作为 DTO 并使用 @Valid 注释
https://www.vinsguru.com/spring-webflux-validation/
I think this is a bug in the framework when you are using coroutines (update , it is, I saw Happy Songs comment). In summary:
"@Validated is indeed not yet Coroutines compliant, we need to fix that by using Coroutines aware methods to discover method parameters."
The trouble is that the signature of the method on your controller is actually enhanced by Spring to have an extra parameter, like this, adding a continuation:
so when the hibernate validator calls getParameter names to get the list of parameters on your method, it thinks there are 4 in total on the request, and then gets an index out of bounds exception trying to get the 4th (index 3).
If you put a breakpoint on the return of this:
and put a breakpoint condition of
index ==3 && a.length <4
you can see what is going on.I'd report it as a bug on the Spring issue tracker.
You might be better off taking an alternative approach, as described here, using a RequestBody as a DTO and using the @Valid annotation
https://www.vinsguru.com/spring-webflux-validation/
感谢快乐歌曲的评论,我现在找到了克服这个障碍的最佳解决方案 Spring Github 问题#23499。
正如此问题的评论和 PaulNuk 的答案中所解释的,运行时将在方法参数中附加一个
Continuation
,这将使 Hibernate 验证器中方法参数名称的索引计算失败。解决方案是更改
ParameterNameDiscoverer.getParameterNames(Method)
方法,并在它是 挂起 函数时添加一个空字符串作为附加参数名称。然后声明一个新的验证器工厂 bean。
从我的 Github 获取完整示例代码。
更新:Spring 6 内置了对 Kotlin 协程控制器的验证支持。
Thanks for the happy songs' comments, I found the best solution by now to overcome this barrier from the Spring Github issues#23499.
As explained in comments of this issue and PaulNuk's answer, there is a
Continuation
will be appended to the method arguments at runtime, which will fail the index computation of the method parameter names in the Hibernate Validator.The solution is changing the
ParameterNameDiscoverer.getParameterNames(Method)
method and adding a empty string as the additional parameter name when it is a suspend function.Then declare a new validator factory bean.
Get the complete sample codes from my Github.
Update: Spring 6 has built-in Validation Support for Kotlin Coroutines Controller.