这是一个非常古老的帖子,但我遇到了类似的问题,我想与大家分享我的经验。
我正在使用其他 API 构建微服务架构。我有一些其他的 GET 服务,它们根据请求参数从后端系统收集数据。
我遵循其余的 API 设计文档,当没有符合查询条件的数据(例如选择零记录)时,我向客户端发送了带有完美 JSON 错误消息的 HTTP 404。
当没有数据发送回客户端时,我准备了一个带有内部错误代码等的完美 JSON 消息,以告知客户端“未找到”的原因,并通过 HTTP 将其发送回客户端404. 效果很好。
后来我创建了一个 rest API 客户端类,它是一个隐藏 HTTP 通信相关代码的简单助手,当我从我的代码中调用我的 rest API 时,我一直使用这个助手。
但我需要编写令人困惑的额外代码,因为 HTTP 404 有两个不同的功能:
- 当 REST API 在给定的 url 中不可用时,真正的 HTTP 404 由运行 REST API 应用程序的应用服务器或 Web 服务器抛出
- 根据查询的 where 条件,当数据库中没有数据时,客户端也会返回 HTTP 404。
重要提示:我的 rest API 错误处理程序会捕获后端服务中出现的所有异常,这意味着如果出现任何错误,我的 rest 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 的情况下检查响应正文。如果我可以解析响应正文,那么我我确定我收到了没有数据可发送回客户端的响应。
如果我无法解析响应,则意味着我从 Web 服务器(而不是从其他 API 应用程序)返回了一个真正的 HTTP 404。
这太令人困惑了,客户端应用程序总是需要做额外的解析来检查 HTTP 404 的真正原因。
老实说,我不喜欢这种解决方案。很混乱,需要一直向客户端添加额外的废话代码。
因此,我决定在这两种不同的场景中使用 HTTP 404,而不是使用以下方法:
- 我不再在我的 REST 应用程序中使用 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);
}
我认为这可以更好地解决这个问题。
如果您有更好的解决方案,请与我们分享。