I've my Spring Boot Web Flux application for quite some time. At this point I wanted to add some exception handlers to my router function:
#Bean
RouterFunction<?> router(final GeneratorHandler generatorHandler) {
return resources("/**", new ClassPathResource("/static/"))
.andOther(route(GET("/generate"), generatorHandler::renderData)
.andRoute(GET("/index"), generatorHandler::renderIndex));
}
So I added another bean like this:
#Bean
HttpHandler httpHandler(final GeneratorHandler generatorHandler) throws Exception {
return WebHttpHandlerBuilder.webHandler(toHttpHandler(router(generatorHandler)))
.prependExceptionHandler((serverWebExchange, exception) -> {
//process here
return null;
})
.build();
}
After this I am having troubles with my view resolver. It can't find any of my views. After investigating I've realized that debugger does not stop in ThymeleafReactiveViewResolver class.
Is that possible that this change changed default view resolver too? How Can I bring it back?
Providing your httpHandler disables quite a lot of support from Spring Boot.
You can declare your own WebExceptionHandler, as a component (even an ordered one) and Spring WebFlux will pick it up for you. Without a more concrete example (or at least the stacktrace/error you're seeing), it's hard to understand what's going on.
Spring Boot now supports error handling in WebFlux applications (see #8625), in case it does what you're trying to achieve.
Related
I am trying to build out an Angular & Spring Boot app with Webflux, and instead of starting by getting bogged down by a full CRUD tutorial with entities and databases I thought I'd start by just seeing if I could get the client to display a string returned by the server, as spring boot's documentation teaches here. To that end, I have the following code:
//Angular client
private currencyGreetingUrl: string;
constructor(private http: HttpClient) {
this.currencyGreetingUrl = 'http://localhost:8080/currency';
}
public getCurrencyGreeting(): Observable<string> {
return this.http.get<string>(this.currencyGreetingUrl);
}
//Spring Boot Web Client
#CrossOrigin(origins = "http://localhost:4200")
public class CurrencyWebClient {
private WebClient client = WebClient.create("http://localhost:8080");
private Mono<ClientResponse> result = client.get()
.uri("/currency")
.accept(MediaType.TEXT_PLAIN)
.exchange();
public String getResult() {
return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
}
}
//Spring boot handler
#Component
public class CurrencyHandler {
public Mono<ServerResponse> currency(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromValue("Hello, Currency On The Go!"));
}
}
//Spring Boot router
#Configuration
public class CurrencyRouter {
#Bean
public RouterFunction<ServerResponse> route(CurrencyHandler currencyHandler) {
return RouterFunctions
.route(RequestPredicates.GET("/currency").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), currencyHandler::currency);
}
}
However, I get this error when running the client and server Access to XMLHttpRequest at 'http://localhost:8080/currency' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I am new to Spring Boot and have been looking around for advice, but I've generally found solutions that involve configurations, controller classes, and other more built out artifacts than what I currently have. How could I get this to work? I appreciate any help.
You have decided to use functional endpoints and you are not using spring security of what i can tell from your tags which means all other answers provided here are faulty.
When using functional endpoints you have to be aware that you have opted out of using the traditional annotation based classes. Which means you loose a lot of the free functionality provided by the spring framework
Functional endpoints are more "low level". So the responsibility falls on you the developer to handle CORS.
If you are a beginner on Spring and webflux i would not pick this route.
The documentation states in the CORS chapter in the official webflux documentation:
You can apply CORS support through the built-in CorsWebFilter, which
is a good fit with functional endpoints.
They even provide an implementation of a standard CORS filter that you can customize to your needs.
#Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// Possibly...
// config.applyPermitDefaultValues()
config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
There is 100s of webpages on the internet that explain CORS and it is the most common question asked in the spring-boot, spring-security tag. I suggest you read up on CORS (which you should of done before asking here).
I highly suggest you start reading here:
Mozilla CORS
Have you configured cors properly?
If not try following:
https://stackoverflow.com/a/67605427/9295125
Please also read the second answer as the posted answer misses one line.
For my purposes when using Webflux with a browser-based front-end where I need to test quickly, I use a CORS-enabling Chrome extension to test quickly. This is obviously not great for production.
If you are in a pure microservice / backend communication situation, you may just need to go with Spring's intended workflow. In my experience, Spring Webflux has some powerful outcomes but finicky setup. Those configuration classes that you mentioned but are avoiding, or annotations or DSL-based solutions for Kotlin are, unfortunately for now, the intended way. In my experience they do work, and once you have them set up it's a matter of making a quick github-ready template for other microservices (I was building Microservices with Spring and Kotlin at the time).
EDIT: I will also just add that those configurations and classes you're avoiding are worth your time, even a morning of your time spent on those will pave the way for a lot of productivity. Webflux is great (and I've used it both with Kotlin and Java) but there are some unavoidable gotchas and configuration differences when you jump to asynchronous / reactive webflux land. The joy in the config comes when you realize you did things right and it's your DB driver that's freaking out when you can push so many requests :) :) :)
Indeed I did need to use the CorsWebFilter. However, after reading a bit on Spring Boot and its Dependency Injection system, and looking at different tangentially related cors implementation in Spring Boot projects that didn't use functional endpoints, I found that I had to place the ``CorsWebFilter``` at the root of my application like so:
#SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
CurrencyWebClient client = new CurrencyWebClient();
System.out.println(client.getResult());
}
#Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
This of course, is not the only way to do it. But it solved this little initial problem I had. Thanks all.
In my Spring Boot project, a couple of REST API endpoints require a class whose initialization takes several minutes. Because of this, it takes several minutes to start the REST API.
Is it possible (using Spring Boot) to make so that these few endpoints are initialized asynchronously i.e. all other endpoints are initialized right away and REST API starts working and these endpoints are initialized whenever the class that they need is initialized and are simply not available to the user before that?
I tried looking into #Async and other ways to make things asynchronous in Spring Boot, but that did not help.
I would really appreciate some help.
Try #Lazy annotation. When it's applied to the spring component, it will be initialized on the first call.
Some resources:
https://www.baeldung.com/spring-lazy-annotation
Java Doc
There's nothing built into Spring to do what you want, but you could implement it yourself by returning a 404 Not Found response while the service is initializing and a 200 OK once it's available. The following is one way to implement that:
#RestController
class ExampleController {
private final Future<SlowInitializationService> service;
ExampleController() {
this.service = ForkJoinPool.commonPool().submit(SlowInitializationService::new);
}
#GetMapping
ResponseEntity<Result> example() throws InterruptedException, ExecutionException {
if (this.service.isDone()) {
return new ResponseEntity<>(this.service.get().perform(), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Rather than using the common pool, you may want to inject an Executor or similar. It'll depend on the rest of your app and how it handles threading.
I am trying to create some authentication mechanism for my spring-boot/graphQL/SPQR-project. I managed to do it on a single service method via #GraphQLRootContext annotation:
#GraphQLMutation(name = "createProblem")
public Problem createProblem(
#GraphQLRootContext DefaultGlobalContext<Object> context,
#GraphQLArgument(name = "problemInput") #Valid Problem problemInput)
{
WebRequest request = (WebRequest) context.getNativeRequest();
String token = request.getHeader("token");
}
here I can extract a JWT token and verify/validate it.
However, I want to do that on a global level without having to add the context parameter to all of my methods.
I am trying to implement a ResolverInterceptor as described here.
However, I don't know how to register this Interceptor with the spring application, so that it is invoked properly. Can anyone help me?
Thanks in advance, Matthias
I'd whole-heartedly suggest you use existing Spring features for handling security instead of rolling out your own, as it already has everything you need to process JWT. Since SPQR will invoke Spring-managed beans, all Spring features will work normally.
If that's for some reason not an option, yes, ResolverInterceptor is the way to go, as it can intercept any resolver invocation and inspect the root context.
For your case, if you want a ResolverInterceptor that is applicable globally (to all resolvers), you can use GlobalResolverInterceptorFactory:
#Bean
public ExtensionProvider<GeneratorConfiguration, ResolverInterceptorFactory> customInterceptors() {
return (config, interceptors) -> interceptors.append(new GlobalResolverInterceptorFactory(customGlobalInterceptors);
}
If you want to optimize a bit and intercept some resolvers only e.g. based on an annotation, you can provide a custom ResolverInterceptorFactory like:
public class AuthInterceptorFactory implements ResolverInterceptorFactory {
List<ResolverInterceptor> authInterceptor = Collections.singletonList(new AuthInterceptor());
#Override
public List<ResolverInterceptor> getInterceptors(ResolverInterceptorFactoryParams params) {
return params.getResolver().getTypedElement().isAnnotationPresent(Auth.class) ? authInterceptor : Collections.emptyList();
}
}
Inside of your ResolverInterceptor if the token in missing or invalid, you want to throw an AbortExecutionException to prevent further execution.
I am using current Spring boot version (1.4.x) and wondering if it has any default timeout for api calls. I have tested it by putting breakpoints but it was keep waiting and didn't time-out.
I was also trying to configure default timeout for all my spring-boot apps by using some annotation or yml settings.
I found couple of alternatives (one of them here) but using callable actually adding extra non-business logic code where setting something in xml bean is out of fashion in latest spring boot applications.
You can try server.connection-timeout=5000 in your application.properties.From the official documentation:
server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
UPDATE:
Just noticed that you use microservice architecture, so in case you need to handle timeouts when communicating between microservices, I would suggest handling it on the client side instead of the server side. If the microservice you are trying to call is overloaded and its performance degrades to the point where it drastically affects the user experience sometimes it's better to return some fallback data than just drop the request.
Imagine we have an e-commerce web-site that has microservice architecture and one of its microservices that gives recommendations to the user becomes extremely slow. In this case, the preferred solution would be to return some fallback data which could be top 10 popular products this month rather than showing 5xx error page to the customer. Moreover, in case subsequent requests fail with a timeout, we can make a decision to avoid sending requests to the 'recommendation-service' and return fallback data immediately. After some time we can try sending a request to the 'recommendation-service' again, and if it became healthy - just use it instead of the fallback data.
This is called Circuit Breaker pattern and there is already an implementation of it in a framework called Hystrix. Here is a nice article explaining it in depth: http://www.baeldung.com/spring-cloud-netflix-hystrix. Spring Cloud Feign + Spring Cloud Hystrix looks really nice especially taking into account that they work with Discovery services out-of-the-box (e.g. Spring Cloud Eureka).
I agree all above options and tried below option in my spring boot application. It works perfectly fine now. Below is the code sample as a bean. Now just need to #Autowire RestTemplate wherever(java class) I need it.
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(15000);
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setReadTimeout(15000);
return restTemplate;
}
There are a couple of ways to do this:
1) Using ClientHttpRequestFactory with RestTemplate:
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(timeinMillis);
factory.setConnectTimeout(timeinMillis);
return factory;
}
2) Second way is to use callable but I guess you have already explored that solution.
The timeout can be set using the connectionTimeout property of Tomcat.
Please refer this answer how to set it for Tomcat.
Configuring maxKeepAliveRequests in Spring Boot embedded Tomcat
You can create a configuration file using annotation #Configuration
For using RestTemplate:
` #Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofMillis(30000))
.setReadTimeout(Duration.ofMillis(30000))
.build();
}`
For WebClient Timeouts:
#Bean
public WebClient webClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().responseTimeout(Duration.ofMillis(30000))
))
.build();
}
After the configuration is done, in a controller or any other file where you want to use this RestTemplate or WebClient just autowire it like:
#Autowired
private RestTemplate restTemplate;
or
#Autowired
private WebClient webClient;
I want to be involved in a reactive programming world with Spring. As I realised, it gives me a choice between two different paradigms: the annotation-based (with well-known to us #Controller, #RequestMapping) and the reactive one (which is intended to resolve an "Annotation Hell").
My problem is a lack of understanding how a typical reactive controller will look like. There are three conceptual interfaces, which I can use in my controller class:
HandlerFunction<T> (1) - I define a method for each specific ServerRequest
which returns a concrete HandlerFunction<T> instance, then register these methods with a router. Right?
RouterFunction (2) and FilterFunction (3) - Is there a specific place where all RequestPredicates with corresponding HandlerFunctions should be placed? Or can I do it separately in each controller (as I used to do with the annotation approach)? If so, how then to notify a global handler (router, if any?) to apply this router part from this controller?
It's how I see a reactive controller "template" by now:
public class Controller {
// handlers
private HandlerFunction<ServerResponse> handleA() {
return request -> ok().body(fromObject("a"));
}
// router
public RouterFunction<?> getRouter() {
return route(GET("/a"), handleA()).and(
route(GET("/b"), handleB()));
}
// filter
public RouterFunction<?> getFilter() {
return route(GET("/c"), handleC()).filter((request, next) -> next.handle(request));
}
}
And, finally, how to say that it is a controller, without marking it with the annotation?
I've read the Spring reference and all posts related to this issue on the official blog. There is a plenty of samples, but all of them are pulled out of context (IMHO) and I can't assemble them into a full picture.
I would appreciate if you could provide a real-world example and good practices of how to organise interactions between these functions.
This is not a real world example, but so far Is how I view some kind of organization on this:
https://github.com/LearningByExample/reactive-ms-example
As far as I concerned:
RouterFunction is the closest analogue to #Controller (#RequestMapping precisely) in terms of new Spring approach:
Incoming requests are routed to handler functions with a
RouterFunction (i.e. Function>). A router function evaluates to a
handler function if it matches; otherwise it returns an empty result.
The RouterFunction has a similar purpose as a #RequestMapping
annotation. However, there is an important distinction: with the
annotation your route is limited to what can be expressed through the
annotation values, and the processing of those is not trivial to
override; with router functions the processing code is right in front
of you: you can override or replace it quite easily.
Then instead of Spring Boot SpringApplication.run in main method your run server manually by :
// route is your route function
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat server = new Tomcat();
Context rootContext = server.addContext("",
System.getProperty("java.io.tmpdir"));
Tomcat.addServlet(rootContext, "servlet", servlet);
rootContext.addServletMapping("/", "servlet");
tomcatServer.start();
There are both reactive and non-reactive approach. It's illustrated on Spring github