我有一个Spring Boot(2.5)应用程序,我需要在其中对远程系统(一个Solr实例,我在其中存储一个非规范化视图)进行REST调用,我可以在其中创建或更新记录。
我真的不在乎我得到的响应(有时远程系统响应很慢),所以我在中进行了这样的异步调用
createIndexForTicket
/
updateIndexForTicket
:
public MyService(WebClient webClient, String solrUpdateUrl) {
this.webClient = webClient;
this.solrUpdateUrl = solrUpdateUrl;
}
public void createIndexForTicket(TicketIndex ticketIndex) {
// build the request
var createRequest = webClient.post()
.uri(solrUpdateUrl);
triggerRequest(createRequest, ticketIndex,"creation");
log.info("payload sent, creating index for ticket {} : {}",ticketIndex.getUserFriendlyTicketId(),ticketIndex);
}
public void updateIndexForTicket(TicketIndex ticketIndex) {
// build the request
var updateRequest = webClient.put()
.uri(solrUpdateUrl + "/" + ticketIndex.getInternalTicketId());
triggerRequest(updateRequest, ticketIndex,"update");
log.info("payload sent, updating index for ticket {} : {}",ticketIndex.getUserFriendlyTicketId(),ticketIndex);
}
private static void triggerRequest(RequestBodySpec requestToSolr,
TicketIndex ticketIndex,
String action) {
requestToSolr.bodyValue(ticketIndex)
.retrieve()
.onStatus(HttpStatus::is2xxSuccessful,
resp -> logSuccess(ticketIndex,action))
.bodyToMono(String.class)
.doOnError(t ->
log.error("problem while performing a "+action+", "
+ "calling Solr for ticket "+ticketIndex.getUserFriendlyTicketId(),t))
.subscribe();
}
它大多数时候都很好用。但我注意到我有时会
Operator called default onErrorDropped
错误,堆栈跟踪如下:
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.NullPointerException
Caused by: java.lang.NullPointerException: null
at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.saveAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:63)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⢠Request to PUT https://myRemoteSolrSystem/services/v2/tickets/dGlja2V0aW5nLXNlcnZpY2UxNDEzNzM1 [DefaultWebClient]
Stack trace:
at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository.saveAuthorizedClient(HttpSessionOAuth2AuthorizedClientRepository.java:63)
at org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository.saveAuthorizedClient(AuthenticatedPrincipalOAuth2AuthorizedClientRepository.java:92)
at org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager.lambda$new$0(DefaultOAuth2AuthorizedClientManager.java:126)
at org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager.authorize(DefaultOAuth2AuthorizedClientManager.java:184)
at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$authorizeClient$24(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:552)
at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:86)
at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227)
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68)
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
查看源代码,我发现
spring-security-oauth2-client
5.5.1,英寸
HttpSessionOAuth2AuthorizedClientRepository.saveAuthorizedClient
@Override
public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal,
HttpServletRequest request, HttpServletResponse response) {
Assert.notNull(authorizedClient, "authorizedClient cannot be null");
Assert.notNull(request, "request cannot be null");
Assert.notNull(response, "response cannot be null");
Map<String, OAuth2AuthorizedClient> authorizedClients = this.getAuthorizedClients(request);
authorizedClients.put(authorizedClient.getClientRegistration().getRegistrationId(), authorizedClient);
request.getSession().setAttribute(this.sessionAttributeName, authorizedClients);
}
l.63,发生异常的是最后一个:
request.getSession().setAttribute(this.sessionAttributeName, authorizedClients);
所以看起来
request.getSession()
返回null。。。但我不知道为什么,我也找不到模式。有时我从同一个线程连续调用两个,一个成功,另一个不成功。。有时两者都失败了,有时两者都成功了。其他时候,我只触发一个调用,但它失败了,而另一个线程或多或少同时执行类似的操作,它就工作了。
被注入的webClient是这样构建的:
@Bean
@Primary
WebClient servletWebClient(ClientRegistrationRepository clientRegistrations,
OAuth2AuthorizedClientRepository authorizedClients) {
var oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
oauth.setDefaultClientRegistrationId("keycloak");
return WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.apply(oauth.oauth2Configuration())
.build();
}
关于我做得不对的地方,或者我可以尝试更好地理解正在发生的事情,有什么提示吗?
谢谢