客户端如何处理API服务器抛出的异常?Spring API示例解析
Hey there! Let's walk through how to handle the exceptions thrown by your bird API (like the EntityNotFoundException you're using) on different client types. First, a quick reminder: your @ControllerAdvice should be translating those Java exceptions into structured HTTP responses with appropriate status codes—for EntityNotFoundException, that's almost certainly a 404 Not Found status, plus a body with error details (like the message you're passing: Bird with id X not found or similar).
Below are common client scenarios and how to handle the errors:
1. Frontend JavaScript (Fetch API)
When using the native Fetch API, you'll need to check if the response is OK first, then handle errors by parsing the response body:
async function getBirdById(birdId) { try { const response = await fetch(`/params?birdId=${birdId}`); if (!response.ok) { // Parse the error response from your ControllerAdvice const errorDetails = await response.json(); throw new Error(`Failed to fetch bird: ${errorDetails.message} (Status: ${response.status})`); } const bird = await response.json(); console.log("Fetched bird:", bird); return bird; } catch (error) { // Handle the error (show to user, log, etc.) console.error("Error fetching bird:", error.message); // Example: Update UI to show error message document.getElementById("error-message").textContent = error.message; } }
2. Frontend JavaScript (Axios)
Axios simplifies error handling by grouping HTTP errors into the catch block, where you can access the response details directly:
async function getBirdById(birdId) { try { const response = await axios.get("/params", { params: { birdId } }); console.log("Fetched bird:", response.data); return response.data; } catch (error) { if (error.response) { // Server responded with a status code outside 2xx range const status = error.response.status; const errorDetails = error.response.data; if (status === 404) { console.error(`Bird with id ${birdId} not found:`, errorDetails.message); // Handle 404 specific logic (e.g., show "Bird not found" to user) } else { console.error("Unexpected error:", errorDetails.message); } } else if (error.request) { // Request was made but no response received console.error("No response from server:", error.request); } else { // Error setting up the request console.error("Request error:", error.message); } } }
3. Java Client (RestTemplate)
If you're calling the API from another Java service using RestTemplate, you can catch specific exceptions like HttpClientErrorException to handle 4xx errors:
public Bird getBirdById(Long birdId) { RestTemplate restTemplate = new RestTemplate(); String url = "/params?birdId=" + birdId; try { return restTemplate.getForObject(url, Bird.class); } catch (HttpClientErrorException.NotFound ex) { // Handle 404 (EntityNotFoundException from your API) System.err.println("Bird not found: " + ex.getResponseBodyAsString()); // Optionally rethrow a custom exception or return a default value throw new CustomBirdNotFoundException(birdId, ex.getMessage()); } catch (HttpClientErrorException ex) { // Handle other 4xx errors (e.g., invalid parameters) System.err.println("Client error: " + ex.getStatusCode() + " - " + ex.getResponseBodyAsString()); throw new CustomApiClientException(ex.getStatusCode(), ex.getMessage()); } catch (HttpServerErrorException ex) { // Handle 5xx server errors System.err.println("Server error: " + ex.getStatusCode()); throw new CustomServerErrorException(ex.getMessage()); } }
4. Java Client (WebClient - Reactive)
For reactive Java clients using WebClient, use onStatus or onErrorResume to handle errors gracefully:
public Mono<Bird> getBirdById(Long birdId) { return WebClient.create() .get() .uri("/params?birdId={birdId}", birdId) .retrieve() .onStatus(HttpStatus::is4xxClientError, response -> { return response.bodyToMono(ErrorDetails.class) .flatMap(errorDetails -> { if (response.statusCode() == HttpStatus.NOT_FOUND) { return Mono.error(new CustomBirdNotFoundException(birdId, errorDetails.getMessage())); } else { return Mono.error(new CustomApiClientException(response.statusCode(), errorDetails.getMessage())); } }); }) .bodyToMono(Bird.class); } // Example ErrorDetails class matching your ControllerAdvice's response format class ErrorDetails { private String message; private String timestamp; // getters and setters }
General Best Practices
- Standardize Error Responses: Make sure your
@ControllerAdvicereturns a consistent error format (e.g., withmessage,errorCode,timestamp) so clients can parse errors uniformly. - Handle Specific Status Codes: Don't just catch generic errors—target specific status codes (like 404 for missing birds, 400 for bad parameters) to provide tailored user feedback.
- Log Errors: Always log error details on the client side for debugging, but show user-friendly messages instead of raw technical details.
内容的提问来源于stack exchange,提问作者Mohammed Nosirat

