简体   繁体   中英

Parse response code based on the status code

I'm trying to implement this code with 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);
        });
    }

// request

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) {
        ..........
    }

As you can see I want to parse the response based on the returned status code. But I get error Local variable response defined in an enclosing scope must be final or effectively final Can you guide me how I can call the two methods parseRawSuccessResponse and parseRawFailedResponse based on the client response codes because I have different return values?

EDIT 1:

I tried this:

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

// parse response:

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

You have several strange things going on in your code.

I will post an example of how you can error handle using 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();

If your application is a pure Webflux client (you are returning a Mono or Flux to the client) you should not call block in your application.

Some of the things in your code that are strange

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

Taken from the spring documentation:

When you use exchange(), you must always use any of the body or toEntity methods of ClientResponse to ensure resources are released and to avoid potential issues with HTTP connection pooling. You can use bodyToMono(Void.class) if no response content is expected. However, if the response does have content, the connection is closed and is not placed back in the pool.

So that will cause a leak. That entire line should be completely removed.

This is very strange too.

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? 
}

You can't declare something outside (response) and use it inside the lambda scope unless it is final. And you can't block on the same thing that you are signalling on. That is because you can't mutate state in lambdas.

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

So how do we change values?

You have to return a new object by using map or flatmap

String value = "Hello ";
String world = Mono.just("World").map(w -> value + w).block();

And this is strange too.

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

Here you do the same thing, you want to parse something and assign it (not allowed by the compiler) then directly after throw an exception. Why parse it if you are going to throw an exception?

So you have some strange things going on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM