Spring Boot在错误响应实体中添加请求主体 [英] Spring Boot add Request Body in the Error Response Entity

查看:114
本文介绍了Spring Boot在错误响应实体中添加请求主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我自己的Exceptionhandler,它扩展了ResponseEntityExceptionHandler

I have my own Exceptionhandler which is extending ResponseEntityExceptionHandler

我能够捕获错误,但是在创建错误响应时请求主体为空

I am able to capture the error but the request body is empty at the time of error response creation

override fun handleHttpMessageNotReadable(e:HttpMessageNotReadableException, headers:HttpHeaders , status:HttpStatus , webRequest: WebRequest):ResponseEntity<Any>{
        val rsp = ErrResponse(
                Data(
                        HttpStatus.BAD_REQUEST.name,
                        e.message!!
                ),**REQUEST-BODY-NEEDED**[customFilter.payload])
        return super.handleExceptionInternal(e, rsp,headers, HttpStatus.BAD_REQUEST, webRequest)
    }

因此,我使用了customRequestfilter来获取主体并在那里捕获主体,但是customRequestFilter的顺序优先级较低,只有在请求之后才会执行.那么有什么方法可以在错误响应中捕获请求正文?

So i have used customRequestfilter to get the body and captured the body there but the order precendence is low for customRequestFilter it will be get executed only after the request . So is there a any way to Capture the request body on the error response?

CustomRequestFilter

CustomRequestFilter

@Component
public class CustomRequestFilter extends OncePerRequestFilter{

 public String payload;
    public Map<String, Object> reqLog =null;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);

        int status = HttpStatus.BAD_REQUEST.value();

        filterChain.doFilter(wrappedRequest, response);
        if (status == response.getStatus()) {
            reqLog = getTrace(wrappedRequest, status);
            payload = getBody(wrappedRequest, reqLog);/** ITS CAPTURING THE BODY HERE SUCCESSFULLY**/
            logTrace(wrappedRequest, reqLog); 
        }

    }

推荐答案

哇,这很棘手!反正...

Wow, that was tricky! Anyway...

创建您的自定义HttpInputMessage,它将委托给原始的自定义文件.

Create your custom HttpInputMessage, which will delegate to the original one.

class CachedHttpInputMessage implements HttpInputMessage {
    private final HttpInputMessage httpInputMessage;
    private ByteArrayOutputStream outputStream;

    CachedHttpInputMessage(final HttpInputMessage httpInputMessage) {
        this.httpInputMessage = httpInputMessage;
    }

    @Override
    public InputStream getBody() throws IOException {
        if (outputStream == null) {
            outputStream = new ByteArrayOutputStream();

            final InputStream body = httpInputMessage.getBody();
            final byte[] buffer = new byte[1024];

            while (true) {
                final int length;
                if (!((length = body.read(buffer)) > -1)) {
                    break;
                }

                outputStream.write(buffer, 0, length);
            }

            outputStream.flush();
        }

        return new ByteArrayInputStream(outputStream.toByteArray());
    }

    @Override
    public HttpHeaders getHeaders() {
        return httpInputMessage.getHeaders();
    }
}

构建您的自定义HttpMessageConverter,然后根据当前使用的扩展名(JacksonGson等)扩展合适的扩展名,并将其注册为第一位.

Build your custom HttpMessageConverter, extending the right one based on the currently used one (Jackson, Gson, etc.), and register it as first.

class CustomHttpMessageConverter extends MappingJackson2HttpMessageConverter {
    @Override
    public Object read(
            final Type type,
            final Class<?> contextClass,
            final HttpInputMessage inputMessage) throws IOException {
        return super.read(type, contextClass, new CachedHttpInputMessage(inputMessage));
    }

    @Override
    protected Object readInternal(
            final Class<?> clazz,
            final HttpInputMessage inputMessage) throws IOException {
        return super.readInternal(clazz, new CachedHttpInputMessage(inputMessage));
    }
}

(或者,您可以像创建CachedHttpInputMessage一样创建通用包装,并包装每个预先配置的HttpMessageConverter,只需将作为输入传递的列表更新为extendMessageConverters)

(alternatively you could create a generic wrapper, like with the CachedHttpInputMessage, and wrap each pre-configured HttpMessageConverter, just update the list passed as input to extendMessageConverters)

@Configuration
class WebConfiguration implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(final List<HttpMessageConverter<?>> converters) {
        converters.add(0, new CustomHttpMessageConverter());
    }

    ...
 }


扔掉自定义Filter,并在ExceptionHandler内使用


Throw away the custom Filter, and inside the ExceptionHandler read the body using

final HttpInputMessage inputMessage = e.getHttpInputMessage();
final InputStream body = inputMessage.getBody();

完成!
请记住要稍微清理一下代码并处理所有可能的异常.

Done!
Remember to clean-up the code a bit and handle all the possible exceptions.

这篇关于Spring Boot在错误响应实体中添加请求主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆