这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
展开这个getRoutingFunction方法,可见会调用renderErrorResponse来处理响应:
@Override
protected RouterFunction
return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
}
打开renderErrorResponse方法,如下所示,真相大白了!
protected Mono
// 取出所有错误信息
Map
// 构造返回的所有信息
return ServerResponse
// 控制返回码
.status(getHttpStatus(error))
// 控制返回ContentType
.contentType(MediaType.APPLICATION_JSON)
// 控制返回内容
.body(BodyInserters.fromValue(error));
}
通过上述代码,咱们得到两个重要结论:
都已经读到了这里,自然要看看getHttpStatus的内部,如下所示,status来自入参:
protected int getHttpStatus(Map
return (int) errorAttributes.get("status");
}
至此,咱们可以得出一个结论:getErrorAttributes方法的返回值是决定返回码和返回body的关键!
来看看这个getErrorAttributes方法的庐山真面吧,在DefaultErrorAttributes.java中(回忆刚才看ErrorWebFluxAutoConfiguration.java的时候,前面曾提到里面的东西都很重要,也包括errorAttributes方法):
public Map
Map
if (Boolean.TRUE.equals(this.includeException)) {
options = options.including(new Include[]{Include.EXCEPTION});
}
if (!options.isIncluded(Include.EXCEPTION)) {
errorAttributes.remove("exception");
}if (!options.isIncluded(Include.STACK_TRACE)) {
errorAttributes.remove("trace");
}
if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
errorAttributes.put("message", "");
}
if (!options.isIncluded(Include.BINDING_ERRORS)) {
errorAttributes.remove("errors");
}
return errorAttributes;
}
篇幅所限,就不再展开上述代码了,直接上结果吧:
打开determineHttpStatus方法,终极答案揭晓,请关注中文注释:
private HttpStatus determineHttpStatus(Throwable error, MergedAnnotation
// 异常对象是不是ResponseStatusException类型
return error instanceof ResponseStatusException
// 如果是ResponseStatusException类型,就调用异常对象的getStatus方法作为返回值
? ((ResponseStatusException)error).getStatus()
// 如果不是ResponseStatusException类型,再看异常类有没有ResponseStatus注解,
// 如果有,就取注解的code属性作为返回值
: (HttpStatus)responseStatusAnnotation.getValue("code", HttpStatus.class)
// 如果异常对象既不是ResponseStatusException类型,也没有ResponseStatus注解,就返回500
.orElse(HttpStatus.INTERNAL_SERVER_ERROR);
}
另外,message字段的内容也确定了:
private String determineMessage(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation) {
// 异常对象是不是BindingResult类型
if (error instanceof BindingResult) {
// 如果是,就用getMessage作为返回值
return error.getMessage();
}
// 如果不是BindingResult类型,就看是不是ResponseStatusException类型
else if (error instanceof ResponseStatusException) {
// 如果是,就用getReason作为返回值
return ((ResponseStatusException)error).getReason();
} else {
// 如果也不是ResponseStatusException类型,
// 就看异常类有没有ResponseStatus注解,如果有就取该注解的reason属性作为返回值
String reason = (String)responseStatusAnnotation.getValue("reason", String.class).orElse("");
if (StringUtils.hasText(reason)) {
return reason;
} else {
// 如果通过注解取得的reason也无效,就返回异常的getMessage字段
return error.getMessage() != null ? error.getMessage() : "";
}
}
}
至此,源码分析已完成,最终的返回码和返回内容究竟如何控制,相信聪明的您心里应该有数了,下一篇《实战篇》咱们趁热打铁,写代码试试精确控制返回码和返回内容
提前剧透,接下来的《实战篇》会有以下内容呈现:
微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界…
手机扫一扫
移动阅读更方便
你可能感兴趣的文章