bmr*_*rki 11 webclient httprequest blocking spring-boot
我正在尝试在两个微服务之间发出 GET 请求(使用 Keycloak 身份验证)。
\n假设微服务 A 正在向微服务 B 请求一些资源。\n微服务 B 有一个 GET 端点,它似乎可以工作,因为在从邮递员或 intelliJ http_client 发出请求时我可以看到正确的响应。
\n在微服务 AI 中尝试发出请求(我确实尝试发出阻塞和非阻塞请求):
\nString response = webClient.mutate()\n .baseUrl(this.serverUri)\n .build().get()\n .uri(uriBuilder -> uriBuilder\n .path("/users/tokens/{id}")\n .build(userId))\n .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)\n .attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction\n .clientRegistrationId("keycloak"))\n .retrieve()\n .bodyToMono(String.class)\n .doOnError(RuntimeException::new)\n .block();\nRun Code Online (Sandbox Code Playgroud)\n webClient.mutate()\n .baseUrl(this.serverUri)\n .build().get()\n .uri(uriBuilder -> uriBuilder\n .path("/users/tokens/{id}")\n .build(userId))\n .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)\n .attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction\n .clientRegistrationId("keycloak"))\n .retrieve()\n .bodyToMono(String.class)\n .subscribe(resp -> {\n JSONObject jsonObject = new JSONObject(resp);\n JSONArray jsonArray = jsonObject.getJSONArray("Tokens");\n for (int i = 0; i < jsonArray.length(); i++) {\n log.info("token :: " + jsonArray.get(i).toString());\n }\n });\nRun Code Online (Sandbox Code Playgroud)\n这是我的WebClient配置:
@Configuration\npublic class WebClientConfiguration {\n\n @Bean\n public OAuth2AuthorizedClientManager authorizedClientManager(\n ClientRegistrationRepository clientRegistrationRepository,\n OAuth2AuthorizedClientRepository authorizedClientRepository) {\n\n OAuth2AuthorizedClientProvider authorizedClientProvider =\n OAuth2AuthorizedClientProviderBuilder.builder()\n .refreshToken()\n .clientCredentials()\n .build();\n\n DefaultOAuth2AuthorizedClientManager authorizedClientManager =\n new DefaultOAuth2AuthorizedClientManager(\n clientRegistrationRepository, authorizedClientRepository);\n authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);\n\n return authorizedClientManager;\n }\n\n @Bean\n WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {\n ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =\n new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);\n return WebClient.builder()\n .apply(oauth2Client.oauth2Configuration())\n .build();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我所做的一切尝试都以这种错误结束:
\n2021-06-29 16:44:07.854 ERROR 390692 --- [oundedElastic-1] reactor.core.publisher.Operators : Operator called default onErrorDropped\n\nreactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: servletRequest cannot be null\nCaused by: java.lang.IllegalArgumentException: servletRequest cannot be null\n at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.5.jar:5.3.5]\n Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: \nError has been observed at the following site(s):\n |_ checkpoint \xe2\x87\xa2 Request to GET https://localhost:8080/api/users/tokens/94a2d4f7-b372-4e13-aa16-7b244c099721 [DefaultWebClient]\nStack trace:\n at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.5.jar:5.3.5]\n at org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager.authorize(DefaultOAuth2AuthorizedClientManager.java:144) ~[spring-security-oauth2-client-5.4.5.jar:5.4.5]\n at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$authorizeClient$24(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:552) ~[spring-security-oauth2-client-5.4.5.jar:5.4.5]\n at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:85) ~[reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227) ~[reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) [reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) [reactor-core-3.4.4.jar:3.4.4]\nRun Code Online (Sandbox Code Playgroud)\n我错过了什么吗?
\n[编辑]
\n按照此处的建议更改 WebClientConfiguration (Spring Security 5 Calling OAuth2 Secured API in Application Runner results in IllegalArgumentException)可以解决问题:
\n2021-06-29 16:44:07.854 ERROR 390692 --- [oundedElastic-1] reactor.core.publisher.Operators : Operator called default onErrorDropped\n\nreactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: servletRequest cannot be null\nCaused by: java.lang.IllegalArgumentException: servletRequest cannot be null\n at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.5.jar:5.3.5]\n Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: \nError has been observed at the following site(s):\n |_ checkpoint \xe2\x87\xa2 Request to GET https://localhost:8080/api/users/tokens/94a2d4f7-b372-4e13-aa16-7b244c099721 [DefaultWebClient]\nStack trace:\n at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.5.jar:5.3.5]\n at org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager.authorize(DefaultOAuth2AuthorizedClientManager.java:144) ~[spring-security-oauth2-client-5.4.5.jar:5.4.5]\n at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$authorizeClient$24(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:552) ~[spring-security-oauth2-client-5.4.5.jar:5.4.5]\n at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:85) ~[reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227) ~[reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) [reactor-core-3.4.4.jar:3.4.4]\n at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) [reactor-core-3.4.4.jar:3.4.4]\nRun Code Online (Sandbox Code Playgroud)\n有人可以解释为什么吗?
\n小智 18
我不确定您在什么上下文中运行它。但错误消息表明该请求不是在 HttpServletRequest 的上下文中启动的。如果您的请求是由调度程序或类似的程序启动的,则不存在 servletRequest。
Spring 文档说您需要 AuthorizedClientServiceOAuth2AuthorizedClientManager 实现来解决这种情况。
DefaultOAuth2AuthorizedClientManager [...] 在 HttpServletRequest 上下文中使用的 OAuth2AuthorizedClientManager 的默认实现。(在 HttpServletRequest 上下文之外操作时,请改用 AuthorizedClientServiceOAuth2AuthorizedClientManager。)
AuthorizedClientServiceOAuth2AuthorizedClientManager [...] OAuth2AuthorizedClientManager 的实现,能够在 HttpServletRequest 的上下文之外运行,例如在调度/后台线程和/或服务层中。(在 HttpServletRequest 上下文中操作时,请改用 DefaultOAuth2AuthorizedClientManager。)
| 归档时间: |
|
| 查看次数: |
5662 次 |
| 最近记录: |