【问题标题】:Return content type for Error Responses based on produces condition of @RequestMapping根据@RequestMapping 的产生条件返回错误响应的内容类型
【发布时间】:2020-06-10 01:03:06
【问题描述】:

我的 REST Web 服务中有自定义错误处理。我有返回 XML / JSON 作为响应的方法。在 SpringBoot 版本 2.0.9 上一切正常。但是在迁移到最新版本 (2.2.4) 后,我的错误处理测试失败了:

Content type expected:<application/xml> but was:<application/json>
Expected :application/xml
Actual   :application/json

经过研究,我发现它与将 Spring 升级到 5.1 版有关。文档:

错误响应的内容协商 @RequestMapping 的产生条件不再影响错误响应的内容类型。

如何在最新的 Spring 早期版本中重现行为?我只想返回 produces 条件中指定的错误的内容类型。

休息方法:

@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<Object> xmlMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {

    Object result = service.call(payload, scriptName);
    return ResponseEntity.ok(new JsonBuilder(result).getContent());
}

@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<Object> jsonMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {
    Object result = service.call(payload, scriptName);
    return ResponseEntity.ok(new JsonBuilder(result).getContent());
}

CustomRestExceptionHandler:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {

        HTTPErrorDTO httpError = new HTTPErrorDTO(HttpStatus.NOT_FOUND, ex.getLocalizedMessage());
        return new ResponseEntity<>(httpError, new HttpHeaders(), httpError.getStatus());
    }

    ....
    // handlers for other exceptions
}

错误 DTO:

@XmlRootElement(name = "Exception")
@XmlAccessorType(XmlAccessType.FIELD)
public class HTTPErrorDTO {

    private HttpStatus status;
    private String message;
    private List<String> errors;
}

相关话题:Spring mvc - Configuring Error handling for XML and JSON Response

---编辑

我尝试添加自定义内容协商配置。但是我的 REST API 的一个客户端向我发送 content-type = "application/x-www-form-urlencoded" 并期望 application/xml 并且不发送任何接受标头。

所以我只能在方法/控制器级别决定内容类型应该是什么格式。

我能否以某种方式从控制器通知异常处理程序,哪一个 应该设置内容类型?

【问题讨论】:

    标签: spring spring-boot spring-mvc spring-restcontroller spring-rest


    【解决方案1】:

    您可以将HandlerMethod 对象传递给异常处理程序方法(即您的问题中的handleResourceNotFoundException)。

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<Object> handleResourceNotFoundException(
        ResourceNotFoundException ex, 
        WebRequest request, 
        HandlerMethod handlerMethod) {
        ........        
    }
    

    HandlerMethod 对象表示引发异常的控制器方法。因此,您可以从对象上的 @RequestMapping 注释中获取 produces 的值。

    RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
    String[] produces = requestMapping.produces();
    ....
    

    在您的问题源代码中,produces 是一个包含元素的数组(即MediaType.APPLICATION_XML_VALUEMediaType.APPLICATION_JSON_VALUE)。

    另见
    https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-exceptionhandler-args

    【讨论】:

      【解决方案2】:

      在您的CustomRestExceptionHandler 中,您可以为ResponseEntity 设置媒体类型。

      return ResponseEntity.status(httpError.getStatus().value())
              .contentType(MediaType.APPLICATION_XML)
              .body(httpError);
      

      【讨论】:

      • 好的,但我想同时支持 JSON 和 XML。我可以以某种方式从控制器通知异常处理程序,应该设置哪一种内容类型?
      • @Bakus123 WebRequest 将允许您访问请求中的 HTTP 标头。
      • 是的,我知道,但我不想根据请求标头来决定。我想指定控制器 X 中的错误始终是 XML,而 Y 中的错误始终是 JSON。
      • @Bakus123 在这种情况下,您可以重写您的异常处理程序方法以接受HandlerMethod 参数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多