HttpMediaTypeNotAcceptableException文本/纯文本响应错误?

时间:2018-07-30 12:33:09

标签: java spring spring-mvc spring-web

我有一个简单的Web服务,它以jsonplain 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。很明显,自定义异常的呈现失败,但是为什么?

4 个答案:

答案 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);
}


}