Springboot v2.0.0.M6 WebClient进行多个重复的HTTP POST调用

时间:2018-11-03 09:17:03

标签: java spring-boot spring-webflux

我正在使用spring-boot版本2.0.0.M6。 我需要从spring-boot应用程序APP1到另一个应用程序(播放框架)APP2进行异步HTTP调用。 因此,如果我需要从APP1到APP2进行20个不同的异步调用,则APP2会收到20个请求,其中有几个是重复的,这意味着这些重复替换了几个不同的请求。 预期:

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。

下面是build.gradle中的spring boot版本

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初始化代码段

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方法的代码

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());
    });

}

已将日志放在客户端代码的端点,此时无法看到多个请求。

可能是WebClient中的一个错误,在多线程环境中URI被交换了。

尝试对WebClient进行更改,但URI仍被交换

请帮助。

Git Repo添加了github.com/praveenk007/ps-demo

1 个答案:

答案 0 :(得分:0)

添加我的一些观察结果:

from flask import send_file response = send_file(absolute_image_path, mimetype='image/jpeg', attachment_filename=name, as_attachment=True) response.headers["x-filename"] = name response.headers["Access-Control-Expose-Headers"] = 'x-filename' return response webClient.get()总是在每次调用webClient.post()的呼叫上返回新的DefaultRequestBodyUriSpec,而且我认为它看起来并不像URI被交换。

URI

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); }

类源

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