Запрос не отправлен без блока () - PullRequest
3 голосов
/ 13 октября 2019

Я хочу использовать этот код клиента webflux для отправки POST-запросов с ответом и без ответа. Я попробовал эту реализацию кода:

public class RestClientBuilder {
    private String token;
    private String username;
    private String password;
    private URL gatewayUrl;
    private SslContextBuilder sslContextBuilder;

    public static RestClientBuilder builder() {
        return new RestClientBuilder();
    }

    public RestClientBuilder token(String token) {
        this.token = validateAndTrim(token, "Token");
        return this;
    }

    public RestClientBuilder usernamePassword(String username, String password) {
        this.username = validateAndTrim(username, "Username");
        this.password = validateAndTrim(password, "Password");
        return this;
    }

    private String validateAndTrim(String value, final String parameter) {
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException(parameter + " is empty");
        }
        return value.trim();
    }

    public RestClientBuilder gatewayUrl(String gatewayUrl) {
        String urlSt = validateAndTrim(gatewayUrl, "Gateway URL");
        try {
            this.gatewayUrl = new URL(urlSt);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("Malformed URL: " + urlSt, e);
        }
        return this;
    }

    public RestClientBuilder truststore(File truststoreFile) {
        getSslContextBuilder().trustManager(truststoreFile);
        return this;
    }

    public RestClientBuilder sslCertificate(File keyCertChainFile, File keyFile, String keyPassword) {
        getSslContextBuilder().keyManager(keyCertChainFile, keyFile, keyPassword);
        return this;
    }

    public RestClient build() throws SSLException {
        SslContext sslContext = sslContextBuilder != null ? sslContextBuilder.build() : null;
        return new RestClient(gatewayUrl.toString(), token, username, password, sslContext);
    }

    private SslContextBuilder getSslContextBuilder() {
        if (sslContextBuilder == null) {
            sslContextBuilder = SslContextBuilder.forClient();
        }
        return sslContextBuilder;
    }

}

Реализация клиента покоя:

public class RestClient {

    private WebClient client;
    private String gatewayUrl;

    public RestClient(String gatewayUrl, String token, String username, String password, SslContext sslContext) {
        this.gatewayUrl = gatewayUrl;
        WebClient.Builder builder = WebClient.builder().baseUrl(gatewayUrl);
        if (sslContext != null) {
            HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
            ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
            builder.clientConnector(httpConnector);
        }
        if (username != null && password != null) {
            builder.filter(basicAuthentication(username, password));
        }
        client = builder.build();
    }

    public Mono<Void> executeOnly(ReportRequest transaction) {
        Mono<ReportRequest> transactionMono = Mono.just(transaction);
        return client.post().uri(gatewayUrl)
                .accept(MediaType.APPLICATION_XML)
                .contentType(MediaType.APPLICATION_XML)
                .body(transactionMono, ReportRequest.class)
                .retrieve()
                .bodyToMono(Void.class);
    }
}

Выполнение удаленных вызовов:

public class ReportingProcessor {

    private String URL2 = "......";

    public void collectEnvironmentData() throws JAXBException {

        ReportRequest report = new ReportRequest();
        report.setVersion("1.0");

        RestClient client = null;
        try {
            client = RestClientBuilder.builder()
                    .gatewayUrl(URL2)
//                .token(contract.getTerminal_token())
//                  .usernamePassword("user", "password")
//                .truststore(new File("server.pem"))
//                .sslCertificate(new File("client.pem"), new File("clientKey.p8"), "secret")
                    .build();
        } catch (SSLException e) {
            e.printStackTrace();
        }

        Mono<Void> result = client.executeOnly(report);
        Void response = result.block();

    }

Когда я удаляю Void response = result.block();запрос не отправлен. Я не могу найти почему. Можете ли вы дать мне несколько советов, как заставить клиентский код работать без использования block().

Ответы [ 3 ]

2 голосов
/ 17 октября 2019

Всякий раз, когда вы работаете с Spring-webflux, вы должны помнить одну вещь. т.е. вам не нужно разрывать свою цепь. потому что это необходимо, кто-то должен позвонить подписаться на вашу цепочку. как это работает со спецификацией RXJava.

если вы разорвете цепочку, вы должны позвонить block(), что не рекомендуется .

, вы должны изменить свой код вследующим образом.

Давайте рассмотрим, что у вас есть обработчик, который выполняет вызов вашего collectEnvironmentData() метода, а ваш метод - вызов удаленной службы.

public  Mono<ServerResponse> handelerMethod(ServerRequest request){
  return collectEnvironmentData().flatMap(aVoid -> ServerResponse.ok().build());
}

ваш метод должен бытьизменено на

public Mono<Void> collectEnvironmentData() throws JAXBException {

ReportRequest report = new ReportRequest();
report.setVersion("1.0");

RestClient client = null;
try {
    client = RestClientBuilder.builder()
            .gatewayUrl(URL2)
//                .token(contract.getTerminal_token())
//                  .usernamePassword("user", "password")
//                .truststore(new File("server.pem"))
//                .sslCertificate(new File("client.pem"), new File("clientKey.p8"), 
//"secret").build();
} catch (SSLException e) {
    e.printStackTrace();
}

return client.executeOnly(report);
}

Измените вашу реализацию описанным выше способом, надеюсь, она будет работать.

1 голос
/ 17 октября 2019

Как бы я реализовал ваш метод:

public Mono<Void> executeOnly(ReportRequest transaction) {
    Mono<ReportRequest> transactionMono = Mono.just(transaction);
    return client.post().uri(gatewayUrl)
        .accept(MediaType.APPLICATION_XML)
        .contentType(MediaType.APPLICATION_XML)
        .body(transaction, ReportRequest.class)
        .exchange()
        .then();
}

И тогда я бы использовал его следующим образом:

client.executeOnly(report).subscribe()

0 голосов
/ 16 октября 2019

Измените method return type на Mono<Void> для сквозной потоковой передачи.

public void collectEnvironmentData() throws JAXBException {

    ReportRequest report = new ReportRequest();
    report.setVersion("1.0");

    RestClient client = null;
    try {
        client = RestClientBuilder.builder()
                .gatewayUrl(URL2)
                .build();
    } catch (SSLException e) {
        e.printStackTrace();
    }

    return client.executeOnly(report);

}

Или вы также можете подписаться на Mono

client.executeOnly(report).subscribe();
...