fix(rest-api): preserve status code from ResponseStatusException
This commit is contained in:
+28
@@ -11,6 +11,7 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||||
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||||
|
|
||||||
@@ -112,6 +113,33 @@ public class GlobalExceptionHandler {
|
|||||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body);
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preserve status code from {@link ResponseStatusException} (Spring's standard
|
||||||
|
* way чтобы throw a specific HTTP status from controller). Without explicit
|
||||||
|
* handler the generic fallback below catches it и turns 401/403/409 в 500 —
|
||||||
|
* каждый use of throw new ResponseStatusException(...) silently downgraded.
|
||||||
|
*
|
||||||
|
* <p>Observed bug: MeNotificationsPreferencesController.requireSub() throws
|
||||||
|
* 401 anonymous, но клиент получал 500 пока этот handler не появился.
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ResponseStatusException.class)
|
||||||
|
public ResponseEntity<ApiErrorResponse> onResponseStatusException(ResponseStatusException e) {
|
||||||
|
int status = e.getStatusCode().value();
|
||||||
|
String reason = e.getReason() != null ? e.getReason() : e.getStatusCode().toString();
|
||||||
|
// Lower-case-snake_case code from status reason — best-effort, falls back
|
||||||
|
// на 'http_<NNN>' если reason missing/multi-word.
|
||||||
|
String code = (e.getReason() != null && !e.getReason().contains(" "))
|
||||||
|
? e.getReason().toLowerCase().replace(' ', '_')
|
||||||
|
: "http_" + status;
|
||||||
|
if (status >= 500) {
|
||||||
|
log.error("ResponseStatusException 5xx: {}", reason, e);
|
||||||
|
} else {
|
||||||
|
log.debug("ResponseStatusException {}: {}", status, reason);
|
||||||
|
}
|
||||||
|
var body = ApiErrorResponse.of(status, code, reason, currentTraceId());
|
||||||
|
return ResponseEntity.status(e.getStatusCode()).body(body);
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public ResponseEntity<ApiErrorResponse> onGeneric(Exception e) {
|
public ResponseEntity<ApiErrorResponse> onGeneric(Exception e) {
|
||||||
log.error("Unhandled exception in REST API", e);
|
log.error("Unhandled exception in REST API", e);
|
||||||
|
|||||||
Reference in New Issue
Block a user