java - spring boot 返回 200,并将“OK”ErrorAttributes 附加到正常的身体响应
问题描述
- Spring Boot 启动器版本:2.3.4.RELEASE
- SPRINGWEB 版本 5.2.8.RELEASE
我的 get 请求开始响应附加到响应正文的无关的“OK”ErrorAttributes,这破坏了上游客户端上的所有 json 反序列化
HTTP/1.1 200
Date: Tue, 26 Jan 2021 07:44:00 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Trace-Id: 55418518fcaa412b
X-Span-Id: 55418518fcaa412b
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: HEAD, GET, OPTIONS, POST, PUT, PATCH, DELETE
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: *
Strict-Transport-Security: max-age=63072000; includeSubdomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
{
"id": "ab160a6c-fe00-4eff-a63d-7c10e1c0607c",
"nickName": "Test User",
"emailAddress": "test.user@test-domain.com",
"phoneNumber": null,
"firstName": "Test",
"lastName": "User'",
"location": {
"id": "a77381f2-5c89-4134-bdad-229ad5e7c9e2",
"latitude": null,
"longitude": null,
"country": "DE",
"stateOrRegion": null,
"city": null
},,
"avatarUrl": null,
"role": "DEFAULT",
"invitationLink": "https://www.test-domain.com/app/app-invite/b666ee33-2046-4ea3-af80-f310756a2eac",
"invitee": null
}{
"timestamp": "2021-01-26T07:44:00.826+00:00",
"status": 200,
"error": "OK",
"message": "",
"path": "/api/users/ab160a6c-fe00-4eff-a63d-7c10e1c0607c"
}
我被困了2天,想知道是否有人知道这个问题以及如何解决它。
更新 我有异常处理程序,返回不同的 json 模型:
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorModel handleValidationExceptions(@Nonnull final MethodArgumentNotValidException ex) {
log.error("Error executing request:", ex);
final List<PropertyErrorModel> propertyErrors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(this::buildProperty)
.collect(toList());
final List<String> globalMessages = ex.getBindingResult().getGlobalErrors()
.stream()
.map(ObjectError::getDefaultMessage)
.filter(Objects::nonNull)
.collect(toList());
return getErrorModelBuilder()
.globalErrors(globalMessages)
.propertyErrors(propertyErrors)
.build();
}
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(ConstraintViolationException.class)
public ErrorModel handleConstraintViolation(@Nonnull final ConstraintViolationException ex) {
log.error("Error executing request:", ex);
final List<PropertyErrorModel> propertyErrors = ex.getConstraintViolations()
.stream()
.map((viol) -> {
return PropertyErrorModel.builder()
.property(viol.getPropertyPath().toString())
.rejectedValue(viol.getInvalidValue())
.message(viol.getMessage())
.build();
})
.collect(toList());
final List<String> globalMessages = List.of(ex.getMessage());
return getErrorModelBuilder()
.code("validation.invalid.property")
.globalErrors(globalMessages)
.propertyErrors(propertyErrors)
.build();
}
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(ValidationException.class)
public ErrorModel handleValidationException(@Nonnull final ValidationException ex) {
log.error("Error executing request:", ex);
final ErrorModel error = ex.getError();
if (error != null) {
return getErrorModelBuilder()
.code(firstNonNull(error.getCode(), "validation.failed"))
.globalErrors(error.getGlobalErrors())
.propertyErrors(error.getPropertyErrors())
.build();
}
final List<PropertyErrorModel> propertyErrors = emptyIfNull(ex.getPropertyErrors());
final List<String> globalMessages = List.of(ex.getMessage());
return getErrorModelBuilder()
.code("validation.failed")
.globalErrors(globalMessages)
.propertyErrors(propertyErrors)
.build();
}
@SneakyThrows
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(AlreadyExistsException.class)
public ErrorModel handleAlreadyExistsException(@Nonnull final AlreadyExistsException ex) {
log.error("Error executing request:", ex);
final Object domain = ex.getDomain();
if (domain == null) {
final List<String> globalMessages = List.of(ex.getMessage());
return getErrorModelBuilder()
.code("validation.failed")
.globalErrors(globalMessages)
.build();
}
final String domainJson = objectMapper.writeValueAsString(domain);
final List<String> globalMessages = List.of(ex.getMessage(), domainJson);
return getErrorModelBuilder()
.code("validation.failed")
.globalErrors(globalMessages)
.build();
}
@ResponseBody
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(UnsupportedFilterPropertyException.class)
public ErrorModel handleUnsupportedFilterPropertyException(@Nonnull final UnsupportedFilterPropertyException ex) {
log.error("Error executing request:", ex);
if (ex.getPropertyError() != null) {
return getErrorModelBuilder()
.code("validation.failed")
.propertyErrors(ex.getPropertyError())
.build();
}
final List<String> globalMessages = List.of(ex.getMessage());
return getErrorModelBuilder()
.code("validation.failed")
.globalErrors(globalMessages)
.build();
}
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(NotFoundException.class)
public ErrorModel handleNotFoundException(@Nonnull final NotFoundException ex) {
log.warn("Error executing request:", ex);
final List<String> globalMessages = List.of(ex.getMessage());
return getErrorModelBuilder()
.code("resource.notfound")
.globalErrors(globalMessages)
.build();
}
@ResponseBody
@ExceptionHandler(Throwable.class)
public ResponseEntity<ErrorModel> fallbackErrorHandler(@Nonnull final Throwable ex) {
log.error("Error executing request:", ex);
final Class<?> errorClass = ex.getClass();
return Optional.ofNullable(errorCodedExceptions.get(errorClass))
.map((errorCode) -> getCodedError(ex, errorCode))
.orElseGet(() -> getDefaultInternalServerError(ex));
}
解决方案
过滤器中旧的脏上下文导致的问题。当抛出异常时,过滤器执行未能清理数据上下文,但不幸的是,在跟踪启动之前这太早失败了。错误日志从未出现在具有适当 trace.id 的 kibana 日志中。(我们的跟踪过滤器的优先级不够高)
然而,需要更多调查的是,与 Spring 框架完全无关的过滤器中的上下文和故障如何仍然允许过滤器链执行继续并调用控制器并返回200
,然后附加一个看似 ErrorAttribute 响应,并带有200
“好的”消息。
推荐阅读
- dart - 如何在颤动中绘制自定义形状
- java - RabbitMQ 在 YAML 文件中配置队列监听器
- swift - 如何让自动布局约束依赖于兄弟视图?
- angular - 为什么组件与硬编码字符串的属性绑定不断出现未定义?
- raku - 可以对无符号变量或常量进行插值吗?
- java - 是否有与 python 的 dict.items()/dict.values()/dict.keys() 等效的 java?
- javascript - 我应该使用 Promise.All 而不是 async.each 吗?
- javascript - 可以溢出的元素:滚动气泡到文档吗?
- python - html文件未正确复制
- node.js - $match 在 mongodb 中查询不同的值