Improve error handling when response is committed
ResponseStatusExceptionHandler lets the error through if it can't change the status while HttpWebHandlerAdapter logs a more helpful message (including status code) but without a full stack trace. Issue: SPR-16231
This commit is contained in:
parent
873cb4e58b
commit
dd0d270ba2
|
|
@ -71,7 +71,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
* <p>TODO:
|
||||
* This definition is currently duplicated between HttpWebHandlerAdapter
|
||||
* and AbstractSockJsSession. It is a candidate for a common utility class.
|
||||
* @see #indicatesDisconnectedClient(Throwable)
|
||||
* @see #isDisconnectedClientError(Throwable)
|
||||
*/
|
||||
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS =
|
||||
new HashSet<>(Arrays.asList("ClientAbortException", "EOFException", "EofException"));
|
||||
|
|
@ -158,8 +158,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
ServerWebExchange exchange = createExchange(request, response);
|
||||
return getDelegate().handle(exchange)
|
||||
.onErrorResume(ex -> {
|
||||
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
logHandleFailure(ex);
|
||||
handleFailure(response, ex);
|
||||
return Mono.empty();
|
||||
})
|
||||
.then(Mono.defer(response::setComplete));
|
||||
|
|
@ -170,8 +169,9 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
getCodecConfigurer(), getLocaleContextResolver());
|
||||
}
|
||||
|
||||
private void logHandleFailure(Throwable ex) {
|
||||
if (indicatesDisconnectedClient(ex)) {
|
||||
private void handleFailure(ServerHttpResponse response, Throwable ex) {
|
||||
boolean statusCodeChanged = response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
if (isDisconnectedClientError(ex)) {
|
||||
if (disconnectedClientLogger.isTraceEnabled()) {
|
||||
disconnectedClientLogger.trace("Looks like the client has gone away", ex);
|
||||
}
|
||||
|
|
@ -181,12 +181,16 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
|
|||
"' to TRACE level.)");
|
||||
}
|
||||
}
|
||||
else if (!statusCodeChanged) {
|
||||
logger.error("Unhandled failure: " + ex.getMessage() + ", " +
|
||||
"response already committed with status=" + response.getStatusCode());
|
||||
}
|
||||
else {
|
||||
logger.error("Failed to handle request", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean indicatesDisconnectedClient(Throwable ex) {
|
||||
private boolean isDisconnectedClientError(Throwable ex) {
|
||||
String message = NestedExceptionUtils.getMostSpecificCause(ex).getMessage();
|
||||
message = (message != null ? message.toLowerCase() : "");
|
||||
String className = ex.getClass().getSimpleName();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
|
|
@ -39,10 +40,11 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
|
|||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||
if (ex instanceof ResponseStatusException) {
|
||||
// Response may be committed but we'll try..
|
||||
logger.debug(ex.getMessage());
|
||||
exchange.getResponse().setStatusCode(((ResponseStatusException) ex).getStatus());
|
||||
return exchange.getResponse().setComplete();
|
||||
HttpStatus status = ((ResponseStatusException) ex).getStatus();
|
||||
if (exchange.getResponse().setStatusCode(status)) {
|
||||
logger.trace(ex.getMessage());
|
||||
return exchange.getResponse().setComplete();
|
||||
}
|
||||
}
|
||||
return Mono.error(ex);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,9 @@ public class ResponseStatusExceptionHandlerTests {
|
|||
public void responseCommitted() throws Exception {
|
||||
Throwable ex = new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Oops");
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.CREATED);
|
||||
this.exchange.getResponse().setComplete()
|
||||
.then(this.handler.handle(this.exchange, ex))
|
||||
.block(Duration.ofSeconds(5));
|
||||
assertEquals(HttpStatus.CREATED, this.exchange.getResponse().getStatusCode());
|
||||
Mono<Void> mono = this.exchange.getResponse().setComplete()
|
||||
.then(this.handler.handle(this.exchange, ex));
|
||||
StepVerifier.create(mono).consumeErrorWith(actual -> assertSame(ex, actual)).verify();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue