2014-10-07 10 views
8

Jak mogę dostosować kod statusu odpowiedzi i dane w treści odpowiedzi, jeśli wystąpi wyjątek w aplikacji internetowej Spring Boot?Spring Boot dostosuj odpowiedź błędu http?

Utworzyłem aplikację internetową, która zgłasza niestandardowy wyjątek, jeśli wystąpi coś nieoczekiwanego z powodu złego stanu wewnętrznego. W związku z tym organizm odpowiedź na wniosek, który wywołał błąd wyglądał:

HTTP/1.1 500 Internal Server Error 
{ 
    "timestamp": 1412685688268, 
    "status": 500, 
    "error": "Internal Server Error", 
    "exception": "com.example.CustomException", 
    "message": null, 
    "path": "/example" 
} 

Teraz chciałbym zmienić kod stanu i ustawić pola w organizmie reakcji. Jednym z rozwiązań, które przyszło mi do głowy było coś takiego:

@ControllerAdvice 
class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { 

    @ExceptionHandler 
    @ResponseStatus(HttpStatus.BAD_REQUEST) 
    @ResponseBody 
    ErrorMessage handleBadCredentials(CustomException e) { 
     return new ErrorMessage("Bad things happened"); 
    } 
} 

@XmlRootElement 
public class ErrorMessage(
    private String error; 

    public ErrorMessage() { 
    } 

    public ErrorMessage(String error) { 
     this.error = error; 
    } 

    public String getError() { 
     return error; 
    } 

    public void setError(String error) { 
     this.error = error; 
    } 
) 

jednak, że utworzony (jako podejrzane) zupełnie inną odpowiedź:

HTTP/1.1 400 Bad Request 
{ 
    "error": "Bad things happened" 
} 
+2

Więc zarówno zrobić i nie chce odpowiedzi niestandardowy? – zeroflagL

+0

@zeroflagL Najlepiej, chciałbym dostosować odpowiedź generowaną przez Spring Boot (jeśli to możliwe). Wdrożenie kompletnego niestandardowego rozwiązania (takiego, jak podane w pytaniu) działa, ale jest mniej przydatne do wielokrotnego użycia między różnymi projektami. – matsev

+1

To wszystko zależy od Ciebie, jeśli niestandardowe rozwiązanie jest przeznaczone do wielokrotnego użytku. FWIW: ciało resposne jest składane przez 'DefaultErrorAttributes # getErrorAttributes'. Możesz wprowadzić tę klasę do swojego 'CustomResponseEntityExceptionHandler'. – zeroflagL

Odpowiedz

7

Kod statusu odpowiedzi HTTP mogą być zmieniane za pomocą metody HttpServletResponse.sendError(int) np

@ExceptionHandler 
void handleIllegalArgumentException(IllegalArgumentException e, HttpServletResponse response) throws IOException { 
    response.sendError(HttpStatus.BAD_REQUEST.value()); 
} 

Alternatywnie, można zadeklarować typ wyjątku w @ExceptionHandler adnotacją jeśli masz dwie lub więcej wyjątków generują ten sam status odpowiedzi:

@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class}) 
void handleBadRequests(HttpServletResponse response) throws IOException { 
    response.sendError(HttpStatus.BAD_REQUEST.value()); 
} 

Więcej informacji można znaleźć w mojej blog post.

5

Jak wspomniała @zeroflagL, Spring Boot wytwarza "standardowy" korpus odpowiedzi na błąd w org.springframework.boot.autoconfigure.web.DefaultErrorAttributes. Podobnie do twoich potrzeb, chciałem wykorzystać to wszystko, ale po prostu rozszerzyć jeszcze jedno pole "typu", które zostało dostarczone przez niektóre z moich wyjątków.

Zrobiłem to, wprowadzając Component, który podklasował DefaultErrorAttributes. Spring Boot automatycznie wybrał i użył mojego zamiast domyślnego.

@Component 
public class ExtendedErrorAttributes extends DefaultErrorAttributes { 
    @Override 
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { 
     final Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace); 

     final Throwable error = super.getError(requestAttributes); 
     if (error instanceof TypeProvider) { 
      final TypeProvider typeProvider = (TypeProvider) error; 
      errorAttributes.put("type", typeProvider.getTypeIdentifier()); 
     } 

     return errorAttributes; 
    } 
} 

Z tym, pojawia się zwiększona ciało odpowiedź JSON, takich jak

{ 
    "timestamp": 1488058582764, 
    "status": 429, 
    "error": "Too Many Requests", 
    "exception": "com.example.ExternalRateLimitException", 
    "message": "DAILY_LIMIT: too many requests", 
    "path": "/api/lookup", 
    "type": "DAILY_LIMIT" 
} 
+0

Świetna odpowiedź! Można go również łatwo zmodyfikować w celu usunięcia atrybutu "wyjątek" z odpowiedzi na błąd w wdrożeniach produkcyjnych, jeśli nie są Państwo zainteresowani wyciekiem tego rodzaju informacji. – Andrew