Це дуже старий пост, але я зіткнувся з подібною проблемою, і я хотів би поділитися своїм досвідом з вами, хлопці.
Я будую мікросервісну архітектуру з API відпочинку. У мене є відпочинок GET, вони збирають дані з бек-енд-системи на основі параметрів запиту.
Я дотримувався решти дизайнерських документів API і відсилав назад HTTP 404 з ідеальним повідомленням про помилку JSON клієнтові, коли не було даних, які б відповідали умовам запиту (наприклад, вибрано нульовий запис).
Коли не було повернено даних клієнту, я підготував ідеальне повідомлення JSON з внутрішнім кодом помилки тощо, щоб повідомити клієнта про причину "Не знайдено", і воно було відправлено назад клієнту з HTTP 404. Це працює чудово.
Пізніше я створив клієнтський клас API для відпочинку, який є легким помічником для приховування коду, пов’язаного зі зв’язком HTTP, і я користувався цим помічником увесь час, коли я дзвонив мені від інших кодів API відпочинку.
Але мені потрібно було написати незрозумілий додатковий код лише тому, що HTTP 404 мав дві різні функції:
- справжній HTTP 404, коли решта API недоступна в даній URL-адресі, його викидає сервер додатків або веб-сервер, де працює інша програма API
- клієнт повертає HTTP 404 також, коли в базі даних немає даних, залежно від умови запиту.
Важливо: Мій обробник помилок API застає всі винятки, що з’являються в сервісі бек-енду, що означає, що в разі будь-якої помилки мій API відпочинку завжди повертається із ідеальним повідомленням JSON з деталями повідомлення.
Це перша версія мого клієнтського допоміжного методу, яка обробляє дві різні відповіді HTTP 404:
public static String getSomething(final String uuid) {
String serviceUrl = getServiceUrl();
String path = "user/" + , uuid);
String requestUrl = serviceUrl + path;
String httpMethod = "GET";
Response response = client
.target(serviceUrl)
.path(path)
.request(ExtendedMediaType.APPLICATION_UTF8)
.get();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
// HTTP 200
return response.readEntity(String.class);
} else {
// confusing code comes here just because
// I need to decide the type of HTTP 404...
// trying to parse response body
try {
String responseBody = response.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
ErrorInfo errorInfo = mapper.readValue(responseBody, ErrorInfo.class);
// re-throw the original exception
throw new MyException(errorInfo);
} catch (IOException e) {
// this is a real HTTP 404
throw new ServiceUnavailableError(response, requestUrl, httpMethod);
}
// this exception will never be thrown
throw new Exception("UNEXPECTED ERRORS, BETTER IF YOU DO NOT SEE IT IN THE LOG");
}
АЛЕ , оскільки мій клієнт Java або JavaScript може отримати два типи HTTP 404 якось мені потрібно перевірити тіло відповіді у випадку HTTP 404. Якщо я можу проаналізувати орган відповіді, то я впевнений, що отримав відповідь там, де був немає даних для повернення клієнту.
Якщо я не в змозі проаналізувати відповідь, це означає, що я отримав реальний HTTP 404 з веб-сервера (а не з решти програми API).
Це так заплутано, і клієнтській програмі завжди потрібно зробити додатковий аналіз, щоб перевірити справжню причину HTTP 404.
Чесно кажучи, мені це рішення не подобається. Це заплутано, потрібно постійно додавати додатковий код фігня.
Тому замість використання HTTP 404 у цих двох різних сценаріях я вирішив зробити наступне:
- Я вже не використовую HTTP 404 як HTTP-код відповіді у своїй програмі відпочинку.
- Я буду використовувати HTTP 204 (без вмісту) замість HTTP 404.
У такому випадку код клієнта може бути більш елегантним:
public static String getString(final String processId, final String key) {
String serviceUrl = getServiceUrl();
String path = String.format("key/%s", key);
String requestUrl = serviceUrl + path;
String httpMethod = "GET";
log(requestUrl);
Response response = client
.target(serviceUrl)
.path(path)
.request(ExtendedMediaType.APPLICATION_JSON_UTF8)
.header(CustomHttpHeader.PROCESS_ID, processId)
.get();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
return response.readEntity(String.class);
} else {
String body = response.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
ErrorInfo errorInfo = mapper.readValue(body, ErrorInfo.class);
throw new MyException(errorInfo);
}
throw new AnyServerError(response, requestUrl, httpMethod);
}
Я думаю, що це вирішує цю проблему краще.
Якщо у вас є краще рішення, будь ласка, поділіться ним з нами.