Springboot v2.0.0.M6 WebClient 进行多次重复的 HTTP POST 调用 [英] Springboot v2.0.0.M6 WebClient making multiple duplicate HTTP POST calls

查看:20
本文介绍了Springboot v2.0.0.M6 WebClient 进行多次重复的 HTTP POST 调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 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 时返回新的 DefaultRequestBodyUriSpeccode> 被调用,我认为它看起来不像 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.

类源

https://github.com/spring-projects/spring-framework/blob/master/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java

这篇关于Springboot v2.0.0.M6 WebClient 进行多次重复的 HTTP POST 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆