springboot返回json格式而非Whitelabel Error Page页面
我们使用springboot做API网关,提供rest接口的时候,如果请求的接口没有实现,springboot默认情况下返回如下的页面:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Jan 16 11:45:32 CST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
API网关建议统一返回json数据格式如下:
{"code":1,"message":"success","time":1547610575320,"body":"hello"}
如果我们没有实现对应的接口,就会出现上面的“Whitelabel Error Page”的错误html页面,而不是返回的json格式。
解决办法是在应用配置文件,如“application.properties”中加入如下配置:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
上面还不够,我们还要使用“@ControllerAdvice”实现统一异常处理。
@ControllerAdvice实现统一异常处理
先来看看统一返回序列化为json的类Result:
public class Result<T> {
/** 自定义状态码 */
private Integer code;
/** 状态码对应的提示信息 */
private String message;
/** 当前时间用于前台,因为前台时间不准确 */
private Long time = System.currentTimeMillis();
/** 返回体 */
private T body;
}
定义一个API网关层运行时异常类GatewayException:
public class GatewayException extends RuntimeException{
private static final long serialVersionUID = 1L;
/**错误码*/
private Integer errorCode;
/**错误消息*/
private String errorMessage;
}
使用注解“@ControllerAdvice”实现统一异常处理类:
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.NoHandlerFoundException;
import cn.lovecto.common.bean.Result;
import cn.lovecto.common.exception.GatewayException;
@ControllerAdvice
@ResponseBody
public class BaseExceptionDemo {
/**
* 统一异常处理
*
* @param e
* @return
*/
@ExceptionHandler({ Exception.class })
public Result<?> processException(Exception e) {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getResponse();
// 默认返回200状态码
response.setStatus(HttpStatus.OK.value());
Result<?> result = null;
if (e instanceof NoHandlerFoundException) {// 处理404
response.setStatus(HttpStatus.NOT_FOUND.value());
result = new Result<String>(HttpStatus.NOT_FOUND.value(),
"Client Error");
} else if (e instanceof GatewayException) {// 网关层自定义的异常明确抛出
GatewayException gatewayException = (GatewayException) e;
result = new Result<String>(gatewayException.getErrorCode(),
gatewayException.getErrorMessage());
} else {// 其他异常,返回500状态码
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
result = new Result<String>(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Internal Server Error");
}
return result;
}
}
创建一个TestController用于模拟以上场景:
@RestController
@RequestMapping(value = "/test")
public class TestController extends BaseController {
@GetMapping("/hello")
public Result<String> basicHello() {
return new Result<String>(ErrorCodeEnum.SUCCESS, "hello");
}
@GetMapping("/error")
public Result<Boolean> error() {
throw new GatewayException(0, "自定义错误");
}
}
访问:http://localhost:8080/test/hello
http状态码为200:
{"code":1,"message":"success","time":1547618674710,"body":"hello"}
访问:http://localhost:8080/test/error
http状态码为200:
{"code":0,"message":"自定义错误","time":1547618775715,"body":null}
访问不存在的url:http://localhost:8080/test/xxx
http状态码为404:
{"code":404,"message":"Client Error","time":1547618821473,"body":null}
处理返回的json里面包含了null字段的情况
看到上面返回的body是null,有时候我们为了减少数据传输,没必要把值为null的对象序列化到json里,所以需要在配置,如“application.properties”加入如下配置(全局配置方式):
spring.jackson.default-property-inclusion=non_null
如果不是全局配置,可以在对应的类属性上加注解方式:
@JsonInclude(JsonInclude.Include.NON_NULL)