Springboot v2.0.0.M6 WebClient 进行多次重复的 HTTP POST 调用 [英] Springboot v2.0.0.M6 WebClient making multiple duplicate HTTP POST calls
问题描述
我使用的是 spring-boot 版本 2.0.0.M6.我需要从 spring-boot 应用程序(例如 APP1)到另一个应用程序(播放框架)(例如 APP2)进行异步 HTTP 调用.因此,如果我需要从 APP1 到 APP2 进行 20 个不同的异步调用,APP2 会收到 20 个请求,其中很少有重复,这意味着这些重复替换了几个不同的请求.预期:
I am using spring-boot version 2.0.0.M6. I need to make async HTTP calls from spring-boot app say APP1 to another app (play framework) say APP2. So if I need to make 20 distinct async calls from APP1 to APP2, APP2 receives 20 requests out of which few are duplicates, which means these duplicates replaced few distinct requests. Expected:
api/v1/call/1
api/v1/call/2
api/v1/call/3
api/v1/call/4
实际:
api/v1/call/1
api/v1/call/2
api/v1/call/4
api/v1/call/4
我正在使用 spring 反应式 WebClient.
I am using spring reactive WebClient.
以下是build.gradle中的spring boot版本
Below is the spring boot version in build.gradle
buildscript {
ext {
springBootVersion = '2.0.0.M6'
//springBootVersion = '2.0.0.BUILD-SNAPSHOT'
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
maven {url "https://plugins.gradle.org/m2/"}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("se.transmode.gradle:gradle-docker:1.2")
}
}
我的 WebClient 初始化代码段
My WebClient init snippet
private WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector((HttpClientOptions.Builder builder) -> builder.disablePool()))
.build();
我的POST方法
public <T> Mono<JsonNode> postClient(String url, T postData) {
return Mono.subscriberContext().flatMap(ctx -> {
String cookieString = ctx.getOrDefault(Constants.SubscriberContextConstnats.COOKIES, StringUtils.EMPTY);
URI uri = URI.create(url);
return webClient.post().uri(uri).body(BodyInserters.fromObject(postData)).header(HttpHeaders.COOKIE, cookieString)
.exchange().flatMap(clientResponse ->
{
return clientResponse.bodyToMono(JsonNode.class);
})
.onErrorMap(err -> new TurtleException(err.getMessage(), err))
.doOnSuccess(jsonData -> {
});
});
}
调用 postClient 方法的代码
The code from where this postClient method is invoked
private void getResultByKey(PremiumRequestHandler request, String key, BrokerConfig brokerConfig) {
/* Live calls for the insurers */
LOG.info("[PREMIUM SERVICE] LIVE CALLLLL MADE FOR: " + key + " AND REQUEST ID: " + request.getRequestId());
String uri = brokerConfig.getHostUrl() + verticalResolver.determineResultUrl(request.getVertical()) + key;
LOG.info("[PREMIUM SERVICE] LIVE CALL WITH URI : " + uri + " FOR REQUEST ID: " + request.getRequestId());
Mono<PremiumResponse> premiumResponse = reactiveWebClient.postClient(uri, request.getPremiumRequest())
.map(json -> PlatformUtils.mapToClass(json, PremiumResponse.class));
premiumResponse.subscribe(resp -> {
resp.getPremiumResults().forEach(result -> {
LOG.info("Key " + result.getKey());
repository.getResultRepoRawType(request.getVertical())
.save(result).subscribe();
saveResult.subscriberContext(ctx -> {
MultiBrokerMongoDBFactory.setDatabaseNameForCurrentThread(brokerConfig.getBroker());
return ctx;
}).subscribe();
});
}, error -> {
LOG.info("[PREMIUM SERVICE] ERROR RECIEVED FOR " + key + " AND REQUEST ID" + request.getRequestId() + " > " + error.getMessage());
});
}
已将日志放在客户端代码的端点处,此时无法看到多个请求.
Had put logs at the end-point in the client code, can not see multiple requests at that point.
可能是 WebClient 中的一个错误,URI 在多线程环境中被交换.
Probably it's a bug in WebClient where URI is getting swapped in multithreaded environment.
尝试改变 WebClient,URI 仍然被交换
Tried mutating WebClient, still the URI is getting swapped
请帮忙.
Git Repo 添加了 github.com/praveenk007/ps-demo
Git Repo added github.com/praveenk007/ps-demo
推荐答案
添加我的一些观察:
webClient.get()
或 webClient.post()
总是在每次调用 URI
时返回新的 DefaultRequestBodyUriSpec
code> 被调用,我认为它看起来不像 URI
被交换.
webClient.get()
or webClient.post()
always returns new DefaultRequestBodyUriSpec
on every call on which URI
being called and I think it does not look like URI
getting swapped.
class DefaultWebClient implements WebClient {
..
@Override
public RequestHeadersUriSpec<?> get() {
return methodInternal(HttpMethod.GET);
}
@Override
public RequestBodyUriSpec post() {
return methodInternal(HttpMethod.POST);
}
..
@Override
public Mono<ClientResponse> exchange() {
ClientRequest request = (this.inserter != null ?
initRequestBuilder().body(this.inserter).build() :
initRequestBuilder().build());
return exchangeFunction.exchange(request).switchIfEmpty(NO_HTTP_CLIENT_RESPONSE_ERROR);
}
private ClientRequest.Builder initRequestBuilder() {
URI uri = (this.uri != null ? this.uri : uriBuilderFactory.expand(""));
return ClientRequest.create(this.httpMethod, uri)
.headers(headers -> headers.addAll(initHeaders()))
.cookies(cookies -> cookies.addAll(initCookies()))
.attributes(attributes -> attributes.putAll(this.attributes));
}
..
}
和 methodInternal
方法如下所示
@SuppressWarnings("unchecked")
private RequestBodyUriSpec methodInternal(HttpMethod httpMethod) {
return new DefaultRequestBodyUriSpec(httpMethod);
}
此外,在发出实际请求的同时,还会创建新的 ClientRequest
.
In addition while making actual request also, new ClientRequest
is created.
类源
这篇关于Springboot v2.0.0.M6 WebClient 进行多次重复的 HTTP POST 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!