Я реализовал глобальный обработчик исключений в своем приложении Spring Boot, следуя этому подходу.
Этот подход возвращает ошибку как тип ResponseEntity<ErrorResponse>, и вот класс ErrorResponse, как вы также можете видеть в этом примере GitHub:
Ответ об ошибке:
public class ErrorResponse {
private final int status;
private final String message;
private String stackTrace;
private List<String> errors;
}
С другой стороны, я реализую класс ApiResponse для форматирования ответа моего Controller, как показано ниже:
АпиОтвет:
public class ApiResponse<T> {
private Long timestamp;
private final String message;
private final T data;
public ApiResponse(Long timestamp, String message) {
this.timestamp = timestamp;
this.message = message;
this.data = data;
}
}
Вот мой метод контроллера, использующий этот
Контроллер:
@GetMapping("/units/{id}")
public ResponseEntity<ApiResponse<UnitResponse>> findById(@PathVariable long id) {
final UnitResponse response = unitService.findById(id);
return ResponseEntity.ok(
new ApiResponse<>(Instant.now(clock).toEpochMilli(), "Success", response));
}
Итак, я думаю, что мне следует объединить 2 типа ответов (ApiResponse и
ErrorResponse). Это правда?
И я попытался использовать объединенный класс ответов вместо Object в GlobalExceptionHandler, но переопределенные методы выдают ошибку, поскольку реализованный метод возвращает Object.
Итак, как мне решить эту проблему и вернуть один и тот же тип ответа в каждом случае (когда есть ошибка или нет ошибки)?
Правильно иметь разные типы ответа на ошибку (общий и легко обрабатываемый) и успех (конкретный для сделанного вызова). Ошибка обрабатывается клиентом для http 4xx и 5xx и конкретным ответом на вызов для Http 2xx.
The problem is that, there are 2 different response types так в чем именно проблема?
@JohnWilliams Спасибо за ваш ответ. Тогда мне не нужно объединять эти два типа ответов, я думаю. НО, у ErrorResponse есть status поле, а у ApiResponse нет. В этой ситуации, когда я проверяю ответ во внешнем интерфейсе, я думаю, что было бы неплохо проверить то же поле (например, статус). Верно? Если да, то должен ли я использовать одно и то же поле для обоих этих двух ответов, добавив поле status к ApiResponse? Что ты предлагаешь?
У @ILyaCyclone ErrorResponse есть status поле, а у ApiResponse его нет. В этой ситуации, когда я проверяю ответ во внешнем интерфейсе, я думаю, что было бы неплохо проверить то же поле (например, статус). Верно? Если да, то должен ли я использовать одно и то же поле для обоих этих двух ответов, добавив поле status к ApiResponse? Что ты предлагаешь?
Вам не нужно объединять классы ошибок и API. В FE вы должны проверять статус HTTP (developer.mozilla.org/en-US/docs/Web/API/Response/status). Если это хорошо (200, 201, 2xx), обработайте response.json() как ApiResponse. Если это плохо (400), тогда response.json() является ErrorResponse. Кстати: на чем написан клиент FE?
@JohnWilliams На самом деле я пытался проверить статус ответа с помощью Postman и не смог найти никаких данных о статусе в теле ответа, когда я вернусь ApiResponse. Итак, вы имеете в виду, что я могу получить статус, когда я проверяю внешний интерфейс, перейдя по ссылке, которую вы прислали? Фронтенд в React. Заранее спасибо.
Статус http не находится в теле ответа - в почтальоне он отображается на панели навигации ответа - справа от вкладок "Body", "Cookie". Рядом с «Статусом»: Понимание (встроенного в протокол http) response.status имеет решающее значение для управления ответами об ошибках. Ссылка объясняет, что такое http.status. В React вы используете fetch() для вызова сервера? или что?
В React я использую fetch, но если есть возможность проверить статус ответа, то конечно можно и другими методами.
@JohnWilliams Итак, вы имеете в виду, что подход, который я использую (опубликованный в моем вопросе), является правильным подходом, и я должен проверять статус ответа и управлять возвращенными данными на основе этого статуса ответа? Или вы могли бы предложить что-нибудь, например. добавить поле статуса в мой ApiResponse?
Ваш подход правильный, но, чтобы быть ясным, не объединяйте apiresdponse с ответом об ошибке и не помещайте информацию об ошибке в apiresponse. Используйте response.status в клиенте для обработки хорошего (http-200) ответа (объект apiresponse) или ответа с ошибкой (http-400) (объект ошибки)




Вы не должны объединять классы ошибок и API. В FE вы должны проверять HTTP-статус. Если это хорошо (200, 201, 2xx), обработайте response.json() как ApiResponse. Если это плохо (400), тогда response.json() является ErrorResponse.
Это пример кода ReactJS, иллюстрирующий, как обрабатываются два ответа:
componentDidMount() {
this.setState({ isLoading: true })
let api_url = 'http://localhost:8080/units/' + '1'; // id is 1
// Now, use JavaScript's native Fetch API to get
// an ApiResponse<UnitResponse>
fetch(api_url)
.then(res => {
if (res.status >= 400) {
// unpack the error
res.json().then(error => {
// here you have the error
console.error('Error returned is ', error);
});
}
return res.json();
})
.then(apiResponse => {
// here you have the ApiResponse<UnitResponse>>
console.info('Response returned is ', apiResponse );
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components
err => {
// this is not the http.status type error
// this is something like 'server not reached'
});
}
Очень странно, что никто больше никогда не использовал такой же тип ответа за исключением.