Describe the bug
Sometimes, when I call a web service, I get a request cannot be null.
Servlet.service() for servlet [dispatcherServlet] in context with path [/api] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: request cannot be null] with root cause
--
|
| java.lang.IllegalArgumentException: request cannot be null
| at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.7.jar!/:5.3.7]
| Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
| Error has been observed at the following site(s):
| \|_ checkpoint ⇢ Request to GET https://some-web-service.io [DefaultWebClient]
| Stack trace:
| at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.7.jar!/:5.3.7]
| at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.removeAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:70) ~[spring-security-oauth2-client-5.5.0.jar!/:5.5.0]
| at
To Reproduce
Use a HttpSessionOAuth2AuthorizedClientRepository implementation.
Define a web client with ServletOAuth2AuthorizedClientExchangeFilterFunction using filter.
WebClient.builder()
.baseUrl(url)
.filter(servletOAuth2AuthorizedClientExchangeFilterFunction)
.build();
I found that in Spring documentation, the filter function is not used that way in WebClient:
WebClient.builder()
.baseUrl(url)
.apply(servletOAuth2AuthorizedClientExchangeFilterFunction.oauth2Configuration())
.build();
It seems that the apply way call a defaultRequest() to populate attributes from RequestContextHolder if servlet request / response are not found.
Expected behavior
I expect not to get a request can not be null and I expect apply and filter to works the same way.
Comment From: jzheaux
Hi, @ecattez. Thanks for reaching out.
For the Servlet-based function, it's necessary to retrieve the HttpServletRequest, HttpServletResponse, and Authentication from the thread setting up the request. Since it's a servlet-based application, these items aren't available in the reactor context when the filter is invoked.
While it would be nice for the two filter functions to be configured in the same way, it's not surprising for things like this to crop up when using reactive APIs in a servlet-based application.
Note, by the way, that oauth2Configuration() is simply a convenience method. You can make your configuration look quite similar by calling the underlying methods yourself:
WebClient.builder()
.baseUrl(url)
.defaultRequest(servletOAuth2AuthorizedClientExchangeFilterFunction.defaultRequest())
.filter(servletOAuth2AuthorizedClientExchangeFilterFunction)
.build();