1.6 服务异常处理
Restful API错误处理分为以下:
- SpringBoot中默认处理机制
- 自定义异常处理
1.6.1 SpringBoot中默认处理机制
当我们随便访问一个不存在的url请求时候,会返回异常:http://127.0.0.1:8088/xxx
出现空白错误页:404
在前后端分离架构下,Restful API往往会有多个渠道访问:浏览器、app等,很多能多终端都会访问以上接口
以上我们是使用浏览器访问,下面我们使用谷歌插件模拟app访问。
Restlet Client
百度云盘下载:链接:https://pan.baidu.com/s/1lbZ-...
提取码:u149
打开Chrome点击右上角三个点按钮->更多工具--扩展程序--选中开发者模式->将下载后的.crx文件拖入,如提示文件无效则将文件后缀名修改为.rar之后解压缩->点击“加载已解压的扩展程序”找到解压的文件夹路径确定
App端请求:
1.设置变量
2.引用变量请求
3.请求不存在的连接:http://127.0.0.1:8088/xxx
SpringBoot默认处理机制在App端返回了json;浏览器发送返回的是html
SpringBoot默认异常处理类源码:
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"}) //补货"/error"的请求
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
this(errorAttributes, errorProperties, Collections.emptyList());
}
public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, errorViewResolvers);
Assert.notNull(errorProperties, "ErrorProperties must not be null");
this.errorProperties = errorProperties;
}
public String getErrorPath() {
return this.errorProperties.getPath();
}
//处理请求头Accept中包含:text/html的请求
@RequestMapping(
produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
}
//接口请求中返回了json
@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = this.getStatus(request);
return new ResponseEntity(body, status);
}
protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
IncludeStacktrace include = this.getErrorProperties().getIncludeStacktrace();
if (include == IncludeStacktrace.ALWAYS) {
return true;
} else {
return include == IncludeStacktrace.ON_TRACE_PARAM ? this.getTraceParameter(request) : false;
}
}
protected ErrorProperties getErrorProperties() {
return this.errorProperties;
}
}
同一个异常,在不同终端返回的异常的设计方法:通过 produces = {"text/html"}验证。
我们使用Restlet Client 测试下存在的创建用户接口不合法校验时候(接口去掉:BindingResult处理类),SpringBoot默认异常处理:
分析:
- 之前我们抛出的异常,压根没有进入我们的业务方法里面就被SpringBoot框架给挡回去了,虽然会返回一些常见的错误码和错误信息供前端提示,但是很多时候使我们自己定义错误信息
- 大部分情况下SpringBoot默认自带的异常处理机制会自动帮我们返回错误信息了,但是在有些情况下不满足我们要求时候,我们需要自定义异常处理。
- SpringBoot自带的浏览器错误处理机制是根据状态码:status=404 来区分错误请求并返回html页面的;所以我们对此类异常处理可以根据状态码定义不同的html页面返回:
在:项目工程resources下创建:resources/error文件夹,里面存放404.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
您访问的页面不存在
</body>
</html>
此时我们再次访问:http://127.0.0.1:8088/xxx时候
我们查看SpringBoot异常处理类源码:
我们在App端访问如下:
1.6.2 自定义异常处理
public class UserNotExistException extends RuntimeException {
private String id;
public UserNotExistException(String id){
super("user not exist");
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
然后我们在接口:DetailInfo中抛出异常
@GetMapping("/{id:\\d+}")
@JsonView(User.UserDetailView.class)
public User DetailInfo(@PathVariable(name = "id") String xxx){
throw new UserNotExistException(xxx);
}
web端请求:
输出自定义的500异常处理页面
app端请求:
上面异常已经使我们定义的异常了,但是异常的属性id没有传出去:
我们定义全局异常处理类:
GeneralException:
此类里面的所有方法,都是处理其他类所抛出的异常,他本身不处理Http请求,他只处理其他类所抛出的异常。 具体处理什么异常?在注解:
@ControllerAdvice
public class GeneralExceptionHandler {
@ExceptionHandler(UserNotExistException.class)
@ResponseBody//map转化成json
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//错误码返回500
public Map<String,Object> handleUserNotExistException(UserNotExistException ex){
Map<String, Object> result = new HashMap<>();
result.put("id",ex.getId());
result.put("message",ex.getMessage());
return result;
}
}
此时浏览器端访问:
此时App接口访问:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。