没有block(),请求不会发送

时间:2019-10-13 14:52:20

标签: java spring spring-boot spring-webflux

我想使用此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 个答案:

答案 0 :(得分:2)

每当您使用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 :(得分:1)

我将如何实现您的方法:

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

答案 2 :(得分:0)

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