根据状态码解析响应码

时间:2019-08-28 07:25:21

标签: java spring spring-boot spring-webflux

我正在尝试使用Spring Web Flux实现此代码:

public Mono<AuthorizeResponse> executeAndReceiveAuthorize(AuthorizeRequest transaction) {
        Mono<AuthorizeRequest> transactionMono = Mono.just(transaction);
        return client.post().uri(checkTrailingSlash(gatewayUrl) + token)
                .......
                .exchange()         
                .flatMap(clientResponse -> {                    
                    if (clientResponse.statusCode().is4xxClientError()) {
                       clientResponse.body((clientHttpResponse, context) -> {
                          return clientHttpResponse.getBody();
                       });
                    return clientResponse.bodyToMono(AuthorizeResponse.class);
                    }
                    if (clientResponse.statusCode().is5xxServerError()) {
                       clientResponse.body((clientHttpResponse, context) -> {
                          return clientHttpResponse.getBody();
                       });
                    return clientResponse.bodyToMono(AuthorizeResponse.class);
                    }
          else
            return clientResponse.bodyToMono(AuthorizeResponse.class);
        });
    }

//请求

public TransactionResponseFactory transactionProcess(AuthorizeRequestFactory tf) throws Exception {
        ......
        TransactionResponseFactory response = null;                         
            try {
                RestClient client = RestClientBuilder.builder()
                        .gatewayUrl(URL)
                        .token(contract.getTerminal_token())
                        .build();

                Mono<AuthorizeResponse> result = client.executeAndReceiveAuthorize(request);

                 result.doOnSuccess(e -> {
                    response = parseRawSuccessResponse(result.block());
                }).doOnError(e -> {
                    response = parseRawFailedResponse(result.block());                  
                    throw new RuntimeException(e);
                })
               .block();   

        } catch (JAXBException e) {
            e.printStackTrace();
        }                                               
        return response;
    }

    private TransactionResponseFactory parseRawSuccessResponse(AuthorizeResponse response) {
        ............
    }

    private TransactionResponseFactory parseRawFailedResponse(AuthorizeResponse response) {
        ..........
    }

如您所见,我想根据返回的状态码来解析响应。 但是我收到错误消息Local variable response defined in an enclosing scope must be final or effectively final,因为我有不同的返回值,您能否指导我如何基于客户端响应代码调用两种方法parseRawSuccessResponseparseRawFailedResponse

编辑1:

我尝试过:

Mono<AuthorizeRequest> transactionMono = Mono.just(transaction);
        return client.post().uri(checkTrailingSlash(gatewayUrl) + token)
                .body(transactionMono, AuthorizeRequest.class)
                .exchange()
                .flatMap(clientResponse -> {
                    if (clientResponse.statusCode().is4xxClientError()) {
                        // We can handle errors by returning a Mono.error so that the event 
                        // chain can trigger on doOnError later in the chain
                        return Mono.error(RuntimeException::new);
                    }
                    return clientResponse.bodyToMono(AuthorizeResponse.class);
                });

//解析响应:

result.map(fooBar -> {
                    return parseRawSuccessResponse(fooBar);
                }).doOnError(throwable -> {                                 
//                  return parseRawFailedResponse(throwable);
                }).block();

1 个答案:

答案 0 :(得分:0)

您的代码中发生了几件奇怪的事情。

我将发布一个示例,说明如何使用WebClient进行错误处理。

final Mono<FooBar> fooBarMono = WebClient.create()
    .get()
    .exchange()
    .flatMap(clientResponse -> {
        if (clientResponse.statusCode().is4xxClientError()) {
            // We can handle errors by returning a Mono.error so that the event 
            // chain can trigger on doOnError later in the chain
            return Mono.error(RuntimeException::new);
        }
        return clientResponse.bodyToMono(FooBar.class);
    });

    return fooBarMono.map(fooBar -> {
        return doSomethingWith(fooBar);
    }).doOnError(throwable -> {
        //Get our exception log something or whatever
    }).block();

如果您的应用程序是纯Webflux客户端(您正在向客户端返回MonoFlux),则不应在应用程序中调用block。

代码中有些奇怪的东西

clientResponse.body((clientHttpResponse, context) -> {
                      return clientHttpResponse.getBody();
                   });

摘自Spring文档:

  

使用exchange()时,必须始终使用任何正文或   ClientResponse的toEntity方法,以确保释放资源   并避免HTTP连接池的潜在问题。您可以   如果没有响应内容,请使用bodyToMono(Void.class)。   但是,如果响应中确实包含内容,则连接已关闭   并且不会放回泳池中。

因此将导致泄漏。整个行应完全删除。

这也很奇怪。

result.doOnSuccess(e -> { // <- e is your value and you are not using it
    response = parseRawSuccessResponse(result.block()); // <- instead you are blocking on the same mono you are in? 
}

除非最终声明,否则您不能在(响应)之外声明某些内容并在lambda范围内使用它。而且您不能阻止正在发出信号的同一件事。那是因为你不能在lambda中改变状态。

// Declaring something outside can't later then be reassigned inside
// a lambda, the compiler will complain.
String value = "Hello ";
final Mono<String> world = Mono.just("World").doOnSuccess(w -> {
    value = w;
});

那么我们如何更改值?

您必须使用mapflatmap

返回一个新对象
String value = "Hello ";
String world = Mono.just("World").map(w -> value + w).block();

这也很奇怪。

.doOnError(e -> {
    response = parseRawFailedResponse(result.block());                  
    throw new RuntimeException(e);
}).block()

在这里您做同样的事情,您想要解析某些东西并分配它(编译器不允许),然后在引发异常后立即进行分配。如果要抛出异常,为什么要解析它?

所以您发生了一些奇怪的事情。