如何在无HttpServletRequest上下文场景下测试Spring Boot WebClient调用
解决方案
第一步:修正现有WebClient配置缺陷
- 给Servlet环境专用的
servletWebClient增加Servlet环境条件注解,避免非Servlet环境下尝试实例化该Bean:
给该Bean添加@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)注解即可,生产环境为Servlet Web应用,该Bean会正常加载,非Servlet测试环境则不会注册。 - 修正调度专用
schedulerWebClient的过滤器实现:当前代码中该实例依然使用了ServletOAuth2AuthorizedClientExchangeFilterFunction,这个过滤器本身强制依赖Servlet请求上下文,哪怕配置了独立的OAuth2AuthorizedClientManager也会触发空指针错误,需要替换为不依赖Servlet环境的通用OAuth2AuthorizedClientExchangeFilterFunction,修正后的代码如下:@Bean @Qualifier("forScheduler") WebClient schedulerWebClient(@Qualifier("authorizedClientManagerForScheduler") OAuth2AuthorizedClientManager authorizedClientManager) { // 替换为通用OAuth2过滤器,不依赖Servlet请求上下文 var oauth = new OAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); oauth.setDefaultClientRegistrationId("keycloak"); return WebClient.builder() .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .apply(oauth.oauth2Configuration()) .build(); }
第二步:编写非Servlet环境集成测试
关闭Web环境的同时手动导入OAuth2客户端自动配置,保证OAuth2相关核心Bean正常加载,测试类示例如下:
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration; import org.springframework.context.annotation.Import; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.reactive.function.client.WebClient; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @Import(OAuth2ClientAutoConfiguration.class) public class SchedulerWebClientTest { @Autowired @Qualifier("forScheduler") private WebClient schedulerWebClient; @Test void testSchedulerWebClientNoServletRequestError() { // 此处替换为你的调度任务逻辑,或者直接调用WebClient发起测试请求 String result = schedulerWebClient.get() .uri("替换为实际要调用的外部服务测试地址") .retrieve() .bodyToMono(String.class) .block(); // 断言返回结果正常,不会抛出servletRequest cannot be null异常 assertNotNull(result); } }
复现原问题验证
如果需要验证原错误场景,只需将schedulerWebClient的过滤器换回ServletOAuth2AuthorizedClientExchangeFilterFunction,再执行上述测试,即可复现生产环境的servletRequest cannot be null错误。
内容的提问来源于stack exchange,提问作者Vincent F
相关产品推荐
相关产品推荐

