我有一个简单的Web服务,它以json
或plain text
的形式返回内容(取决于客户端的accept
http标头)。
问题:如果在text/plain
请求期间发生错误,Spring会以某种方式返回406 Not Acceptable
。这是错误的,因为spring还可以将错误作为普通错误文本写出,而且应该绝对保留400
错误状态:
@RestController
public class TestServlet {
@PostMapping(value = "/test", produces = {APPLICATION_JSON_VALUE, TEXT_PLAIN_VALUE, "text/csv"})
public Object post() {
throw new BadRequestException("bad req");
}
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
public BadRequestException(String msg) {
super(msg);
}
}
带有accept=application/json
的POST请求:
{
"timestamp": "2018-07-30T14:26:02",
"status": 400,
"error": "Bad Request",
"message": "bad req",
"path": "/test"
}
带有accept=text/csv
(或text/plain
)的BUT显示状态为406 Not Acceptable
的空响应。
我还注意到DispatcherServlet.processDispatchResult()
被两次调用:首先是我的BadRequest
异常,第二次是HttpMediaTypeNotAcceptableException
。很明显,自定义异常的呈现失败,但是为什么?
答案 0 :(得分:1)
问题是限制性的 Accept 标头只允许一种内容类型作为响应。如果出现错误,Spring MVC 需要处理 BadRequestException
并使用注册的 HttpMessageConverter
生成所需的内容类型。
默认情况下,Spring Boot 没有消息转换器来直接从任何对象生成 text/plain
。您可以注册一个 ObjectToStringHttpMessageConverter
(因为 bean 应该适用于 Spring Boot)以允许这样做,并且您将获得 BadRequestException.toString()
作为响应正文的结果。
我假设 text/csv
存在类似问题,但我不确定您的 CSV 消息转换设置如何。
答案 1 :(得分:0)
写在“产生”中的条件将用于响应的媒体类型确定为“文本/ csv”。因此,对于成功的情况,它可以正常工作,**
但是当您使用JSON正文呈现异常时, 成为一个问题,而是给您406。
**
答案 2 :(得分:0)
在最新版本的Spring框架中,该问题已解决,但是在旧版本中,如Spring JIRA comments中所述,您应该从请求中删除HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
属性
代码可能是这样的:
@RestControllerAdvice
public class ExampleControllerAdvice {
@ExceptionHandler(value = Exception.class)
public ResponseEntity<?> handleException(HttpServletRequest request, Exception e) {
request.removeAttribute(
HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
return new ResponseEntity<?>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
答案 3 :(得分:0)
我们可以处理建议中的异常
@ControllerAdvice
类ExceptionHandler {
@ExceptionHandler(value = {HttpMediaTypeNotAcceptableException.class})
公共ResponseEntity handleMediaTypeException(HttpMediaTypeNotAcceptableException e){
APIErrorResponse apiErrorResponse =新的APIErrorResponse();
apiErrorResponse.setErrorCode(“在此处设置自定义代码”);
apiErrorResponse.setErrorMessage(“在此处/此处设置自定义消息,此处我们可以使用来自异常对象的消息,即e.getMessage()”);
返回新的ResponseEntity <>(errorDetails,HttpStatus.BAD_REQUEST);
}