Spring Boot 返回值额外增加了一些字段
Spring Boot About 6,156 words现象
状态码为:200
。
在统一的返回值后面,又额外加了timestamp
、status
、error
、path
字段。
{
"code": "0",
"errorMsg": null,
"data": {
...
}
}{
"timestamp": "2023-06-27T02:45:34.128+00:00",
"status": 200,
"error": "OK",
"path": "/test"
}
排查
发现使用了zalando
的logbook
脱敏组件。版本:2.14.0
。
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>2.14.0</version>
</dependency>
错误日志
[2023-06-27 14:16:56.836] [http-nio-8081-exec-2] [ERROR] [org.apache.juli.logging.DirectJDKLog : log : 175] [] [OpenAPI] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError: null
at java.base/java.util.regex.Pattern$BranchConn.match(Pattern.java:4716)
at java.base/java.util.regex.Pattern$Curly.match0(Pattern.java:4411)
at java.base/java.util.regex.Pattern$Curly.match0(Pattern.java:4411)
...
at java.base/java.util.regex.Pattern$Curly.match0(Pattern.java:4411)
...
at java.base/java.util.regex.Matcher.find(Matcher.java:746)
at org.zalando.logbook.json.PrimitiveJsonPropertyBodyFilter.filter(PrimitiveJsonPropertyBodyFilter.java:83)
at org.zalando.logbook.NonMergeableBodyFilterPair.filter(NonMergeableBodyFilterPair.java:21)
at org.zalando.logbook.FilteredHttpResponse.getBodyAsString(FilteredHttpResponse.java:50)
at org.zalando.logbook.json.JsonHttpLogFormatter.prepareBody(JsonHttpLogFormatter.java:64)
at org.zalando.logbook.StructuredHttpLogFormatter.prepare(StructuredHttpLogFormatter.java:95)
at org.zalando.logbook.StructuredHttpLogFormatter.format(StructuredHttpLogFormatter.java:26)
at org.zalando.logbook.DefaultSink.write(DefaultSink.java:26)
at org.zalando.logbook.Strategy.write(Strategy.java:119)
at org.zalando.logbook.DefaultLogbook$1.lambda$process$0(DefaultLogbook.java:55)
at org.zalando.logbook.servlet.LogbookFilter.write(LogbookFilter.java:87)
at org.zalando.logbook.servlet.LogbookFilter.doFilter(LogbookFilter.java:80)
at org.zalando.logbook.servlet.HttpFilter.doFilter(HttpFilter.java:31)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
原因
对于大的JSON
返回值,会一直在while
循环中,从而导致StackOverflowError
,从而走到SpringMVC
的ErrorController
逻辑,额外增加了字段。
logbook
// org.zalando.logbook.json.PrimitiveJsonPropertyBodyFilter#filter
@Override
public String filter(@Nullable final String contentType, final String body) {
if (JsonMediaType.JSON.test(contentType)) {
final Matcher matcher = pattern.matcher(body);
final StringBuffer result = new StringBuffer(body.length());
while (matcher.find()) {
if (predicate.test(matcher.group("property"))) {
// this preserves whitespaces around properties
matcher.appendReplacement(result, "${key}");
result.append(replacement.apply(
matcher.group("property"),
matcher.group("propertyValue")));
} else {
matcher.appendReplacement(result, "$0");
}
}
matcher.appendTail(result);
return result.toString();
}
return body;
}
BasicErrorController & DefaultErrorAttributes
// org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity<>(status);
}
Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
}
// org.springframework.boot.web.servlet.error.DefaultErrorAttributes#getErrorAttributes(org.springframework.web.context.request.WebRequest, boolean)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
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.remove("message");
}
if (!options.isIncluded(Include.BINDING_ERRORS)) {
errorAttributes.remove("errors");
}
return errorAttributes;
}
private Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, webRequest);
addErrorDetails(errorAttributes, webRequest, includeStackTrace);
addPath(errorAttributes, webRequest);
return errorAttributes;
}
}
@ControllerAdvice
对于这个问题使用@ControllerAdvice
,并不能抓到Throwable
的异常。
参考
Views: 1,072 · Posted: 2023-07-10
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓
Loading...