I'm creating simple controller server for spring reactive project. While setting redirection to another location, I have found an error when calling http://localhost:8080/
:
There was an unexpected error (type=Internal Server Error, status=500).
ModelAttributeMethodArgumentResolver does not support multi-value reactive type wrapper: interface reactor.netty.http.server.HttpServerResponse
java.lang.IllegalStateException: ModelAttributeMethodArgumentResolver does not support multi-value reactive type wrapper: interface reactor.netty.http.server.HttpServerResponse
at org.springframework.util.Assert.state(Assert.java:94)
at org.springframework.web.reactive.result.method.annotation.ModelAttributeMethodArgumentResolver.resolveArgument(ModelAttributeMethodArgumentResolver.java:112)
at org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:123)
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:190)
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:133)
at org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter.lambda$handle$1(RequestMappingHandlerAdapter.java:200)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
...
This is the controller code:
import reactor.core.publisher.Mono;
import reactor.netty.http.server.HttpServerResponse;
@RestController
public class BaseController {
@GetMapping("/")
public Mono<Void> indexController(HttpServerResponse response) {
return response.sendRedirect("/api/v1");
}
// ...
}
I expected it to be redirected from localhost:8080/
to localhost:8080/api/v1
. But I've got the above exception.
Try a URL http://localhost:8080/HelloWeb/index and you should see the following result if everything is fine with your Spring Web Application. Click the "Redirect Page" button to submit the form and to get the final redirected page.
There are several reasons for this: Spring MVC can't run on Netty. both infrastructure will compete for the same job (for example, serving static resources, the mappings, etc) mixing both runtime models within the same container is not a good idea and is likely to perform badly or just not work at all.
You can use RedirectAttributes to store flash attributes and they will be automatically propagated to the "output" FlashMap of the current request. A RedirectAttributes model is empty when the method is called and is never used unless the method returns a redirect view name or a RedirectView.
What is Spring WebFlux ? Spring WebFlux is parallel version of Spring MVC and supports fully non-blocking reactive streams. It support the back pressure concept and uses Netty as inbuilt server to run reactive applications. If you are familiar with Spring MVC programming style, you can easily work on webflux also.
Redirecting with Controller MVC good-old approach:
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.net.URI;
@RestController
public class Controller {
@GetMapping("/")
public Mono<Void> indexController(ServerHttpResponse response) {
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("/api/v1"));
return response.setComplete();
}
}
If someone would prefer functional Router/Handler approach might investigate: How to redirect a request in spring webflux?.
@Bean
RouterFunction<ServerResponse> routerFunction() {
return route(GET("/"), req ->
ServerResponse.temporaryRedirect(URI.create("/api/v1"))
.build());
}
When using @RestController
a ResponseEntity
can work as well (here implemented using kotlin coroutines) :
@RestController
class SomeController() {
suspend fun someMethod() : ResponseEntity<Unit> {
return ResponseEntity
.status(HttpStatus.TEMPORARY_REDIRECT)
.location(URI.create("/api/v1"))
.build()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With