如何在异常处理程序中访问访问请求主体

Jul*_*ian 5 java spring-boot

我们有一个 Spring Boot 应用程序,我们的控制器期望在我们的端点之一中有一个 XML 文档元素:

@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(...);
}
Run Code Online (Sandbox Code Playgroud)

我们有自己的 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
    }
Run Code Online (Sandbox Code Playgroud)

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

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

提前感谢您或您的意见。

Cod*_*ode 0

您可以创建一个请求scoperd实体来保留请求主体,

@Component
@RequestScope
public class RequestDetails {
    private JAXBElement<my.company.stuff.request.Document> requestBody;
    //getter setter
}
Run Code Online (Sandbox Code Playgroud)

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

@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(...);
}
Run Code Online (Sandbox Code Playgroud)

然后注入RequestDetailsExceptionHandler使用,

Document requestBody = requestDetails.getRequestBody();
Run Code Online (Sandbox Code Playgroud)