【问题标题】:How to get access to access request body inside Exception Handler如何访问异常处理程序中的访问请求正文
【发布时间】:2020-08-31 21:42:32
【问题描述】:

我们有一个 spring boot 应用程序,我们的控制器需要一个 XML Document 元素在我们的端点之一:

@PostMapping(value = "/api/v1/do-stuff",
        consumes = APPLICATION_XML_VALUE,
        produces = APPLICATION_XML_VALUE)
public ResponseEntity<JAXBElement<my.company.stuff.resposnse.Document>> doStuff(
        @RequestBody JAXBElement<my.company.stuff.request.Document> requestBody,
        Principal principal) throws Exception {

    // Doing some suff here and returning the result
    return stuffService.doStuff(...);
}

我们有自己的 Jaxb2Marshaller 实例,我们在其中设置了请求文档和响应文档的模式,用于在请求和响应主体与我们的域对象之间进行编组和取消编组。当请求到来时,Spring Boot 框架将在请求正文和域请求文档之间进行转换。有时请求正文没有通过 XSD 架构验证,因此它甚至没有到达我们的控制器。

抛出的异常被传递给我们的自定义扩展org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler,我们希望在其中为我们的应用程序客户端创建最有意义的错误响应:

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request) {
        // Getting access to the request body would be very beneficial here
    }

我们的问题是有时传递给我们的处理程序的异常没有足够的详细信息,我们希望能够访问请求正文以便能够自定义我们对客户端的响应。但是,请求的输入流不再可访问,因为它已经从部分模式验证(转换)处理中读取,因此任何以这种方式访问​​它的尝试都会失败。

另一方面,我们试图实现的目标是非常常识,只是想知道我们是否采用了错误的方法,以及实现相同目标的更好设计是什么。将控制器更改为期望纯文本并验证并将其转换为控制器内的请求文档并不是一个真正的选择。

提前感谢您或您的意见。

【问题讨论】:

  • 嗨@Julian,我也有同样的问题。你找到解决这个问题的方法了吗?谢谢!

标签: java spring-boot


【解决方案1】:

你可以再添加一个参数 HttpServletRequest ,你就会得到请求。 示例:

@RestControllerAdvice
@Slf4j
public class InvalidRequestExceptionHandler {

    @ExceptionHandler(InvalidRequestException.class)
    public ResponseEntity<BusinessLogicValidationError> handle(InvalidRequestException exception, HttpServletRequest request) {

    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("some text");
    }
}

【讨论】:

  • 问题不是获取请求,而是获取请求正文。
【解决方案2】:

你应该使用ControllerAdvice

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    protected void handleHttpMessageNotReadableException(HttpMessageNotReadableException ex,
                                                              HttpServletResponse response,HttpServletRequest request {
      // you have full access to both request and response
    }

无论如何,如果这不适合您的情况,我认为您可以:

@Autowired
private HttpServletRequest request;

【讨论】:

  • 我可以从我的WebRequest 请求参数中获取HttpServletRequest,这根本不是问题。我的问题是如何获得请求正文。尝试使用请求 InputStream 获取它不起作用,因为流已经从其中读取了所有字节。
【解决方案3】:

您可以创建一个请求范围实体来保留请求正文,

@Component
@RequestScope
public class RequestDetails {
    private JAXBElement<my.company.stuff.request.Document> requestBody;
    //getter setter
}

在控制器中使用它来设置请求正文,

@Inject
RequestDetails requestDetails;

public ResponseEntity<JAXBElement<my.company.stuff.resposnse.Document>> doStuff(
        @RequestBody JAXBElement<my.company.stuff.request.Document> requestBody,
        Principal principal) throws Exception {
    requestDetails.setRequestBody(requestBody); //set request body
    // Doing some suff here and returning the result
    return stuffService.doStuff(...);
}

然后将RequestDetails注入ExceptionHandler并使用,

Document requestBody = requestDetails.getRequestBody();

【讨论】:

  • 你指的是org.springframework.web.servlet.support.RequestContext吗?如果是这样,它没有 getRequestBody() 方法
  • 更新了答案。我希望它有用。
  • 正如我在问题中所说,当文档未通过 XSD 验证时,它根本不会到达控制器。异常在到达控制器之前发生,一旦发生,它就会传递给错误处理程序。在该错误处理程序中,最好能够访问请求正文并构建更有意义的错误响应。
  • 然后只需创建一个请求拦截器并将正文设置在那里。
猜你喜欢
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
相关资源
最近更新 更多