【问题标题】:Spring Boot add Request Body in the Error Response EntitySpring Boot 在错误响应实体中添加请求正文
【发布时间】:2019-07-17 13:55:40
【问题描述】:

我有自己的异常处理程序,它正在扩展 ResponseEntityExceptionHandler

我能够捕获错误,但在创建错误响应时请求正文为空

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 的顺序优先级很低,它只会在请求之后执行。那么有什么方法可以在错误响应中捕获请求正文?

自定义请求过滤器

@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); 
        }

    }

【问题讨论】:

  • 这是 Kotlin,不是 Java。我将编辑标签。
  • 你在哪里抛出 HttpMessageNotReadable 异常?它是在 Spring Framework 内部抛出的吗?刚查了一下,是从HttpMessageConverter抛出的
  • 是的,它被春天扔了
  • LppEdd Seconds 部分用 Java 编写的代码。只是 java 和 kotlin 的混合体,因为第二部分也将是其他基于 java 的项目的库

标签: java spring spring-boot kotlin


【解决方案1】:

哇,这很棘手!总之……

创建您的自定义HttpInputMessage,它将委托给原始@。

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 等)的基础上扩展右侧的,并将其注册为第一个。

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


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

    ...
 }

扔掉自定义的Filter,在ExceptionHandler里面使用读取正文

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

完成!
记得稍微清理一下代码并处理所有可能的异常。

【讨论】:

  • 当我尝试读取正文 java.io.IOException: Stream closed at java.io.PushbackInputStream.ensureOpen(PushbackInputStream.java:74) at java.io.PushbackInputStream .read(PushbackInputStream.java:135)
  • @sankar 你在维护 ContentCachingRequestWrapper 吗?
  • 我在执行 e.getHttpInputMessage() 时评论了这些。
  • @sankar 我认为您仍然需要在过滤器中使用它,并将其传递给过滤器链。否则 InputStream 将被关闭。
  • 好的,现在我也遇到了同样的错误。现在我将 WrappedRequest 传递给过滤器链,这有点奇怪,应该在框架 filterChain.doFilter(wrappedRequest, response);
猜你喜欢
  • 2021-05-09
  • 2019-05-24
  • 1970-01-01
  • 2019-09-23
  • 2022-01-13
  • 1970-01-01
  • 2017-09-24
  • 2017-07-30
  • 2017-03-07
相关资源
最近更新 更多