SpringBoot 2.6.2 及表单数据
SpringBoot 2.6.2 and form data
我正在试验如下所示的控制器端点:
@PostMapping("login")
fun login(
@RequestParam username: String,
@RequestParam password: String): ResponseEntity<LoginResponse> {
// ...
}
请求是从 HTML 表单发送的,如下所示:
<form action="../api/login" method="POST">
<input id="username" type="text" placeholder="Enter Username" name="username" required=""><br>
<input id="password" type="password" placeholder="Enter Password" name="password" required=""><br>
<button type="submit">Login</button>
</form>
这与 spring 引导版本 2.6.1 完美配合。但是升级到2.6.2版本,加上spring云网关后,突然就不能用了。
日志将如下所示:
2022-01-11 14:33:09,618 [reactor-http-nio-2] DEBUG o.s.web.method.HandlerMethod - [3d97dc1a-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:13027] Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.example.models.LoginResponse> com.example.login(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String): 400 BAD_REQUEST "Required String parameter 'username' is not present"
2022-01-11 14:33:09,656 [reactor-http-nio-2] DEBUG org.springframework.web.HttpLogging - [3d97dc1a-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:13027] Resolved [ServerWebInputException: 400 BAD_REQUEST "Required String parameter 'username' is not present"] for HTTP POST /api/login
我尝试了各种方法,例如:
@PostMapping(value = ["login"], consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun login(
@RequestParam paramMap: MultiValueMap<String,String>
): ResponseEntity<LoginResponse> {
//...
}
但这也失败了,并显示以下日志:
2022-01-11 14:10:11,589 [reactor-http-nio-2] DEBUG o.s.w.s.a.HttpWebHandlerAdapter - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] HTTP POST "/api/login"
2022-01-11 14:10:11,601 [reactor-http-nio-2] DEBUG o.s.w.r.r.m.a.RequestMappingHandlerMapping - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] Mapped to com.example.ApiController#login(MultiValueMap)
2022-01-11 14:10:12,945 [reactor-http-nio-2] DEBUG o.s.w.r.r.m.a.RequestBodyMethodArgumentResolver - Form data is accessed via ServerWebExchange.getFormData() in WebFlux.
2022-01-11 14:10:21,640 [reactor-http-nio-2] DEBUG o.s.web.method.HandlerMethod - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.example.models.LoginResponse> com.example.ApiController.login(org.springframework.util.MultiValueMap<java.lang.String, java.lang.String>): 415 UNSUPPORTED_MEDIA_TYPE
我猜 415 UNSUPPORTED_MEDIA_TYPE
的错误消息只是误导,它以某种方式无法映射表单数据。我该怎么做才能让 API 再次接受表单数据?
尝试类似的东西:
@PostMapping(value = ["login"], consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun login(@RequestParam paramMap: Map<String,String>): ResponseEntity<LoginCodeResponse> {
// ...
}
实际上调用了 get,但 paramMap 始终为空。
实际有效的是以下内容:
@RestController
@RequestMapping("api")
class HelloWorldController(){
@GetMapping("hello")
fun helloName(@RequestParam name: String): String {
return "Hello $name!"
}
}
因此对于正常的获取请求 @RequestParam
按预期工作。
更新
我似乎归结为以下几点。使用 spring-boot-starter-webflux 似乎表单数据的 @RequestParam
不起作用。这好像是a known issue.
implementation("org.springframework.boot:spring-boot-starter-webflux")
使用 spring-boot-starter-web 它 @RequestParam
用于表单数据工作。
implementation("org.springframework.boot:spring-boot-starter-web")
但此启动器与 spring 云不兼容。同时使用 spring-boot-starter-web 和设置 spring.main.web-application-type=reactive
使 spring 云网关以 spring 开始-boot-starter-web 但对于表单数据仍然 @RequestParam
不起作用。
为了通过 POST 使用 webflux 获取数据,我使用很好地提供的 awaitFormData 方法执行了以下操作:
@PostMapping("authorize", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
suspend fun login(exchange: ServerWebExchange): ResponseEntity<LoginResponse> {
val formData = exchange.awaitFormData()
val username = formData["username"]?.get(0)!!
val password = formData["password"]?.get(0)!!
这只是解决方案要点的草图。如果你想使用它,你还应该添加一些适当的错误处理来检查参数是否存在,否则你只会有一个错误 500,这并没有说明很多。
我正在试验如下所示的控制器端点:
@PostMapping("login")
fun login(
@RequestParam username: String,
@RequestParam password: String): ResponseEntity<LoginResponse> {
// ...
}
请求是从 HTML 表单发送的,如下所示:
<form action="../api/login" method="POST">
<input id="username" type="text" placeholder="Enter Username" name="username" required=""><br>
<input id="password" type="password" placeholder="Enter Password" name="password" required=""><br>
<button type="submit">Login</button>
</form>
这与 spring 引导版本 2.6.1 完美配合。但是升级到2.6.2版本,加上spring云网关后,突然就不能用了。 日志将如下所示:
2022-01-11 14:33:09,618 [reactor-http-nio-2] DEBUG o.s.web.method.HandlerMethod - [3d97dc1a-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:13027] Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.example.models.LoginResponse> com.example.login(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String): 400 BAD_REQUEST "Required String parameter 'username' is not present"
2022-01-11 14:33:09,656 [reactor-http-nio-2] DEBUG org.springframework.web.HttpLogging - [3d97dc1a-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:13027] Resolved [ServerWebInputException: 400 BAD_REQUEST "Required String parameter 'username' is not present"] for HTTP POST /api/login
我尝试了各种方法,例如:
@PostMapping(value = ["login"], consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun login(
@RequestParam paramMap: MultiValueMap<String,String>
): ResponseEntity<LoginResponse> {
//...
}
但这也失败了,并显示以下日志:
2022-01-11 14:10:11,589 [reactor-http-nio-2] DEBUG o.s.w.s.a.HttpWebHandlerAdapter - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] HTTP POST "/api/login"
2022-01-11 14:10:11,601 [reactor-http-nio-2] DEBUG o.s.w.r.r.m.a.RequestMappingHandlerMapping - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] Mapped to com.example.ApiController#login(MultiValueMap)
2022-01-11 14:10:12,945 [reactor-http-nio-2] DEBUG o.s.w.r.r.m.a.RequestBodyMethodArgumentResolver - Form data is accessed via ServerWebExchange.getFormData() in WebFlux.
2022-01-11 14:10:21,640 [reactor-http-nio-2] DEBUG o.s.web.method.HandlerMethod - [656327b1-1, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:11772] Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.example.models.LoginResponse> com.example.ApiController.login(org.springframework.util.MultiValueMap<java.lang.String, java.lang.String>): 415 UNSUPPORTED_MEDIA_TYPE
我猜 415 UNSUPPORTED_MEDIA_TYPE
的错误消息只是误导,它以某种方式无法映射表单数据。我该怎么做才能让 API 再次接受表单数据?
尝试类似的东西:
@PostMapping(value = ["login"], consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun login(@RequestParam paramMap: Map<String,String>): ResponseEntity<LoginCodeResponse> {
// ...
}
实际上调用了 get,但 paramMap 始终为空。
实际有效的是以下内容:
@RestController
@RequestMapping("api")
class HelloWorldController(){
@GetMapping("hello")
fun helloName(@RequestParam name: String): String {
return "Hello $name!"
}
}
因此对于正常的获取请求 @RequestParam
按预期工作。
更新
我似乎归结为以下几点。使用 spring-boot-starter-webflux 似乎表单数据的 @RequestParam
不起作用。这好像是a known issue.
implementation("org.springframework.boot:spring-boot-starter-webflux")
使用 spring-boot-starter-web 它 @RequestParam
用于表单数据工作。
implementation("org.springframework.boot:spring-boot-starter-web")
但此启动器与 spring 云不兼容。同时使用 spring-boot-starter-web 和设置 spring.main.web-application-type=reactive
使 spring 云网关以 spring 开始-boot-starter-web 但对于表单数据仍然 @RequestParam
不起作用。
为了通过 POST 使用 webflux 获取数据,我使用很好地提供的 awaitFormData 方法执行了以下操作:
@PostMapping("authorize", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
suspend fun login(exchange: ServerWebExchange): ResponseEntity<LoginResponse> {
val formData = exchange.awaitFormData()
val username = formData["username"]?.get(0)!!
val password = formData["password"]?.get(0)!!
这只是解决方案要点的草图。如果你想使用它,你还应该添加一些适当的错误处理来检查参数是否存在,否则你只会有一个错误 500,这并没有说明很多。