使用 ContainerResponseFilter 获取响应主体

问题描述 投票:0回答:2

我正在尝试使用

getEntityStream()
ContainerResponseContext
来捕获响应实体流。下面是代码:

public String getResponseEntityStream(ContainerResponseContext context) throws IOException {

    OutputStream originalStream = context.getEntityStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    context.setEntityStream(baos);

    String body = baos.toString();
    baos.writeTo(originalStream);
    baos.close();
    context.setEntityStream(originalStream);
    return body;
}

我在下面的代码中调用上面的方法来获取整个响应流:

@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
        throws IOException {

    StringBuilder sbResponse = new StringBuilder();
    
    sbResponse.append(" - Response Entity Class: ").append(responseContext.getEntityClass())
        .append(System.getProperty("line.separator"));

    sbResponse.append(" - Response Entity Stream: ").append(getResponseEntityStream(responseContext))
        .append(System.getProperty("line.separator"));

    System.out.println("HTTP RESPONSE : " + "\n" + sbResponse.toString());
}

我的问题:

在上面的代码中,

Response Entity Stream
始终为空。在我对流进行一些处理之前,我只是想读取整个响应实体流并打印它以显示原始流的样子。我在哪里犯了错误?提前致谢。

更新: 我可以使用

WriterInterceptor
获取响应正文。然而,
WriterInterceptor
只有在有响应负载时才会被调用。我正在使用
ContainerResponseFilter
,因为即使没有有效负载,我也想阅读响应详细信息。此外,Writer Interceptor 不能像
getStatus()
那样帮助
getStatusInfo()
ContainerResponseFilter
。有没有一种方法可以将
ContainerResponseFilter
WriterInterceptor
的数据组合在一个字符串中,并在日志中打印整个响应。可能是通过使用 Thread Local?

java spring-boot jersey jax-rs
2个回答
1
投票

ContainerResponseContext
这里混淆了两种方法:

  • getEntity() - 在写入之前返回实际的 Java 实体对象
  • getOutputStream() - 返回用于写入实体的
    OutputStream
    。该实体是在编写器拦截器阶段编写的。

OutputStream
可以由用户提供的
OutputStream
进行修饰,它执行所需的操作,例如,它记录信息并将数据写入原始流。这个新的装饰器
OutputStream
可以通过ContainerResponseContext#setEntityStream()注册。

Jersey 带有 LoggingFeature / ServerLoggingFilter / LoggingInterceptor。他们一起做这个日志记录,过滤器装饰原始

OutputStream
,他们记录实体、标题和其他响应相关信息。

在那些 Jersey 类中,您可以看到如何使用 ContainerRequestContext#setProperty()WriterInterceptorContext#getProperty 将信息从

Filter
传递到
Interceptor


0
投票

我认为对方法的使用存在误解

ContainerResponseContext#getEntityStream()
。一个人不应该从
OutputStream
.

阅读

正如@jan-supol 在他的回答中所说,例如,您可以用记录器装饰

OutputStream

但是,如果您仍想按照您的方式记录您的响应,您可以直接检索实体。

你写的代码:

    OutputStream originalStream = context.getEntityStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); // it's empty
    context.setEntityStream(baos); // why? you're replacing the original os by this one
    String body = baos.toString(); // empty stream, empty string
    baos.writeTo(originalStream); // you're writing your empty stream to os, which doesn't affect the os
    baos.close();
    context.setEntityStream(originalStream); // assignment rollback?
    return body; // returning an empty string

我会这样做的方式:

    @Override
    public void filter(ContainerRequestContext request, ContainerResponseContext response) {
        if (response.hasEntity()) {
            StringBuilder sb = new StringBuilder();
            sb.append(" - Response Entity Class: ").append(response.getEntityClass())
                    .append(System.getProperty("line.separator"));
            // in order to work, you should guarantee that entity has reasonable #toString implementation
            Object entity = response.getEntity();
            sb.append(" - Response Entity Stream: ").append(entity.toString())
                    .append(System.getProperty("line.separator"));
            System.out.println("HTTP RESPONSE : " + "\n" + sb.toString());
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.