将 body 添加到 404 Not Found 异常
Add a body to a 404 Not Found Exception
在使用 JHipster 生成的 REST API 中,我想抛出一些 404 异常。通常用
完成
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
这实际上导致了对 xhr 请求的 404 响应。问题是在前端,JHipster 用
解析响应
angular.fromJson(result)
当 404 是实际响应时,这样的结果为空,这使得解析失败。
如果我指向一个未映射的 URI,假设 /api/user
而我的控制器映射到 /api/users
(注意复数)我从 API 得到的 404 有一个 body 在其中:
{
"timestamp": "2016-04-25T18:33:19.947+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/user/myuser/contact"
}
在 angular 中正确解析。
如何创建这样的 body?这个异常是由 spring 抛出的还是 tomcat 谁抛出的?
我试过这个:Trigger 404 in Spring-MVC controller?但是我无法设置响应的参数。
基本思路
第一个选项是定义错误对象并将它们 return 定义为 404 Not Found
主体。类似以下内容:
Map<String, String> errors = ....;
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);
您可以抛出一个 Exception
,而不是 return 一个典型的 ResponseEntity
,它会被解析为一个 404 Not Found
。假设你有一个 NotFoundException
像:
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {}
然后如果你在你的控制器中抛出这个异常,你会看到类似的东西:
{
"timestamp":1461621047967,
"status":404,
"error":"Not Found",
"exception":"NotFoundException",
"message":"No message available",
"path":"/greet"
}
如果您想自定义消息和正文的其他部分,您应该为 NotFoundException
定义一个 ExceptionHandler
。
引入异常层次结构
如果您正在创建 RESTful API 并希望有不同的 错误代码 和 错误消息 对于不同的异常情况,您可以创建表示这些情况的异常层次结构,并从每个异常中提取消息和代码。
例如,您可以引入一个异常,例如 APIException
,它是您的控制器抛出的所有其他异常的超级 class。这个 class 定义了一个 code/message 对,例如:
public class APIException extends RuntimeException {
private final int code;
private final String message;
APIException(int code, String message) {
this.code = code;
this.message = message;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
每个子class 根据异常的性质可以为这对提供一些合理的值。例如,我们可以有一个 InvalidStateException
:
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class InvalidStateException extends APIException {
public InvalidStateException() {
super(1, "Application is in invalid state");
}
}
或者那个臭名昭著的未找到的:
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class SomethingNotFoundException extends APIException {
public SomethingNotFoundException() {
super(2, "Couldn't find something!");
}
}
然后我们应该定义一个 ErrorController
来捕获这些异常并将它们转换为有意义的 JSON 表示。该错误控制器可能如下所示:
@RestController
public class APIExceptionHandler extends AbstractErrorController {
private static final String ERROR_PATH = "/error";
private final ErrorAttributes errorAttributes;
@Autowired
public APIExceptionHandler(ErrorAttributes errorAttributes) {
super(errorAttributes);
this.errorAttributes = errorAttributes;
}
@RequestMapping(path = ERROR_PATH)
public ResponseEntity<?> handleError(HttpServletRequest request) {
HttpStatus status = getStatus(request);
Map<String, Object> errors = getErrorAttributes(request, false);
getApiException(request).ifPresent(apiError -> {
errors.put("message" , apiError.message());
errors.put("code", apiError.code());
});
// If you don't want to expose exception!
errors.remove("exception");
return ResponseEntity.status(status).body(errors);
}
@Override
public String getErrorPath() {
return ERROR_PATH;
}
private Optional<APIException> getApiException(HttpServletRequest request) {
RequestAttributes attributes = new ServletRequestAttributes(request);
Throwable throwable = errorAttributes.getError(attributes);
if (throwable instanceof APIException) {
APIException exception = (APIException) throwable;
return Optional.of(exception);
}
return Optional.empty();
}
}
所以,如果你抛出一个 SomethingNotFoundException
,returned JSON 就像:
{
"timestamp":1461621047967,
"status":404,
"error":"Not Found",
"message":"Couldn't find something!",
"code": 2,
"path":"/greet"
}
如果你想return一些消息或用你的错误代码进行测试,我想你可以这样做
@ResponseBody
public ResponseEntity somthing() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
}
抛出新的 ResponseStatusException(HttpStatus.NOT_FOUND, "消息");
在使用 JHipster 生成的 REST API 中,我想抛出一些 404 异常。通常用
完成return new ResponseEntity<>(HttpStatus.NOT_FOUND);
这实际上导致了对 xhr 请求的 404 响应。问题是在前端,JHipster 用
解析响应angular.fromJson(result)
当 404 是实际响应时,这样的结果为空,这使得解析失败。
如果我指向一个未映射的 URI,假设 /api/user
而我的控制器映射到 /api/users
(注意复数)我从 API 得到的 404 有一个 body 在其中:
{
"timestamp": "2016-04-25T18:33:19.947+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/user/myuser/contact"
}
在 angular 中正确解析。
如何创建这样的 body?这个异常是由 spring 抛出的还是 tomcat 谁抛出的?
我试过这个:Trigger 404 in Spring-MVC controller?但是我无法设置响应的参数。
基本思路
第一个选项是定义错误对象并将它们 return 定义为 404 Not Found
主体。类似以下内容:
Map<String, String> errors = ....;
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);
您可以抛出一个 Exception
,而不是 return 一个典型的 ResponseEntity
,它会被解析为一个 404 Not Found
。假设你有一个 NotFoundException
像:
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {}
然后如果你在你的控制器中抛出这个异常,你会看到类似的东西:
{
"timestamp":1461621047967,
"status":404,
"error":"Not Found",
"exception":"NotFoundException",
"message":"No message available",
"path":"/greet"
}
如果您想自定义消息和正文的其他部分,您应该为 NotFoundException
定义一个 ExceptionHandler
。
引入异常层次结构
如果您正在创建 RESTful API 并希望有不同的 错误代码 和 错误消息 对于不同的异常情况,您可以创建表示这些情况的异常层次结构,并从每个异常中提取消息和代码。
例如,您可以引入一个异常,例如 APIException
,它是您的控制器抛出的所有其他异常的超级 class。这个 class 定义了一个 code/message 对,例如:
public class APIException extends RuntimeException {
private final int code;
private final String message;
APIException(int code, String message) {
this.code = code;
this.message = message;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
每个子class 根据异常的性质可以为这对提供一些合理的值。例如,我们可以有一个 InvalidStateException
:
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class InvalidStateException extends APIException {
public InvalidStateException() {
super(1, "Application is in invalid state");
}
}
或者那个臭名昭著的未找到的:
@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class SomethingNotFoundException extends APIException {
public SomethingNotFoundException() {
super(2, "Couldn't find something!");
}
}
然后我们应该定义一个 ErrorController
来捕获这些异常并将它们转换为有意义的 JSON 表示。该错误控制器可能如下所示:
@RestController
public class APIExceptionHandler extends AbstractErrorController {
private static final String ERROR_PATH = "/error";
private final ErrorAttributes errorAttributes;
@Autowired
public APIExceptionHandler(ErrorAttributes errorAttributes) {
super(errorAttributes);
this.errorAttributes = errorAttributes;
}
@RequestMapping(path = ERROR_PATH)
public ResponseEntity<?> handleError(HttpServletRequest request) {
HttpStatus status = getStatus(request);
Map<String, Object> errors = getErrorAttributes(request, false);
getApiException(request).ifPresent(apiError -> {
errors.put("message" , apiError.message());
errors.put("code", apiError.code());
});
// If you don't want to expose exception!
errors.remove("exception");
return ResponseEntity.status(status).body(errors);
}
@Override
public String getErrorPath() {
return ERROR_PATH;
}
private Optional<APIException> getApiException(HttpServletRequest request) {
RequestAttributes attributes = new ServletRequestAttributes(request);
Throwable throwable = errorAttributes.getError(attributes);
if (throwable instanceof APIException) {
APIException exception = (APIException) throwable;
return Optional.of(exception);
}
return Optional.empty();
}
}
所以,如果你抛出一个 SomethingNotFoundException
,returned JSON 就像:
{
"timestamp":1461621047967,
"status":404,
"error":"Not Found",
"message":"Couldn't find something!",
"code": 2,
"path":"/greet"
}
如果你想return一些消息或用你的错误代码进行测试,我想你可以这样做
@ResponseBody
public ResponseEntity somthing() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
}
抛出新的 ResponseStatusException(HttpStatus.NOT_FOUND, "消息");