ace*_*123 4 spring illegalstateexception spring-boot spring-webflux
一般来说,我对 Webflux 和 Spring 很陌生,并且在设置处理 POST 请求的简单服务器时遇到了麻烦:
WebfluxtestApplication.java
package com.test.webfluxtest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@SpringBootApplication
@RestController
public class WebfluxtestApplication {
public static void main(String[] args) {
SpringApplication.run(WebfluxtestApplication.class, args);
}
@PostMapping
public Mono<Person> processPerson(@RequestBody Mono<Person> personMono){
Person person = personMono.block();
person.setAge(42);
return Mono.just(person);
}
}
Run Code Online (Sandbox Code Playgroud)
如下Person:
人.java
package com.test.webfluxtest;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Person {
private String name;
private int age;
public Person(@JsonProperty String name, @JsonProperty int age){
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return this.name + " " + this.age;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我发送 POST 请求时,我收到一个java.lang.IllegalStateException. 更具体地说,这是堆栈跟踪的顶部:
java.lang.IllegalStateException: In a WebFlux application, form data is accessed via ServerWebExchange.getFormData().
at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.readBody(AbstractMessageReaderArgumentResolver.java:158) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ? HTTP POST "/" [ExceptionHandlingWebHandler]
Stack trace:
at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.readBody(AbstractMessageReaderArgumentResolver.java:158) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.readBody(AbstractMessageReaderArgumentResolver.java:126) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.annotation.RequestBodyMethodArgumentResolver.resolveArgument(RequestBodyMethodArgumentResolver.java:64) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:123) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:200) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:137) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter.lambda$handle$1(RequestMappingHandlerAdapter.java:200) ~[spring-webflux-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) ~[reactor-core-3.3.0.RELEASE.jar:3.3.0.RELEASE]
Run Code Online (Sandbox Code Playgroud)
问题似乎是我@RequestBody直接使用标签而不是通过访问表单数据ServerWebExchange。但是,我在网上看到了多个@RequestBody与 WebFlux 一起使用的示例,没有任何问题。比如Spring本身的框架文档。
使用标签会产生类似的问题IllegalStateExceptions(如此处),但具有不同的异常消息。
我使用了 spring-boot 初始化程序来创建项目的等级文件,但我自己没有更改它。
有人知道问题是什么以及我该如何解决它吗?
编辑
多亏了 Aviad Levy,我才找到了问题所在。也就是说,POST 请求的格式不正确,因为正文是在 url 中编码发送的。为了使其正常工作,我必须确保请求正文是 JSON 对象,并且Content-Type标头设置为application/json. 我只是仍然困惑为什么使用错误的格式会引发该特定消息的异常。
更新:此答案假设您想要发布表单数据,这是基于错误消息的假设。
简短的答案是使用@ModelAttribute. 此外,您不能阻塞,除非切换线程(例如通过publishOn()运算符),但在这里您不必这样做。这有效:
@PostMapping("/test")
public Mono<Person> processPerson(@ModelAttribute Mono<Person> personMono){
return personMono.doOnNext(p -> p.setAge(42));
}
Run Code Online (Sandbox Code Playgroud)
长答案是@RequestBody仅支持MultiValueMap<String,String>表单数据。要将表单数据绑定到对象上,您需要使用@ModelAttribute. 然而,在这种情况下,您看到的错误消息是关于不同的内容。它试图防止主体被消耗两次,一次通过访问表单参数的代码exchange.getFormData(),第二次通过声明控制器方法参数。因此,错误消息仍然适用,但前提是您尝试绑定到MultiValueMap.
还有改进的空间。至少,错误消息可以得到改善。此外,@RequestBody对表单数据的支持还可以得到改进,因为显然您想要做的事情是可能的,并且您不必记住切换注释。
您介意在https://github.com/spring-projects/spring-framework/issues中创建一个问题吗?
| 归档时间: |
|
| 查看次数: |
10349 次 |
| 最近记录: |