Java 获取我的请求的请求主体

Java 获取我的请求的请求主体,java,jax-rs,Java,Jax Rs,如何获得我将要执行的实际请求主体 Invocation i = webTarget.path("somepath") .request(MediaType.APPLICATION_JSON) .buildPut(Entity.entity(account, MediaType.APPLICATION_JSON)); log.debug(i.... ); // I want to log the request 您可以尝试包装实体的Outputstream。首先,

如何获得我将要执行的实际请求主体

    Invocation i = webTarget.path("somepath")
    .request(MediaType.APPLICATION_JSON)
    .buildPut(Entity.entity(account, MediaType.APPLICATION_JSON));
    log.debug(i.... ); // I want to log the request

您可以尝试包装实体的Outputstream。首先,通过使用
javax.ws.rs.client.ClientRequestFilter
向ClientRequestContext添加自定义输出流

Client client = ClientBuilder.newClient().register(MyLoggingFilter.class);

public class MyLoggingOutputStreamWrapper extends OutputStream{
  static final Logger logger = Logger.getLogger(...);
  ByteArrayOutputStream myBuffer = new ...
  private OutputStream target;

  public MyLoggingOutputStreamWrapper(OutputStream target){ ...

  // will be smarter to implement write(byte [], int, int) and call it from here 
  public void write(byte [] data){
    myBuffer.write(data);
    target.write(data);
  }

  ... // other methods to delegate to target, especially the other write method

  public void close(){
    // not sure, if converting the buffer to a string is enough. may be in a different encoding than the platform default
    logger.log(myBuffer.toString());
    target.close();
  }
}

@Provider
public class MyLoggingFilter implements ClientRequestFilter{
  // implement the ClientRequestFilter.filter method
  @Override
  public void filter(ClientRequestContext requestContext) throws IOException {
     requestContext.setEntityOutputstream(new MyLoggingOutputStreamWrapper(requestContext.getEntityOutputstream()));
  }
我不确定outputstream在哪一点用于序列化数据。可能是在您调用buildPut()的时候,但更有可能是在webclient访问时


另一种方法是获取底层的HttpClient并在那里注册一些侦听器以获取主体。

我也遇到了类似的问题。我无法使用Jersey LoggingFilter(以及2.23中的新LoggingFeature),因为我需要自定义输出。有关使用其他选项的信息,请参见以下文章:

为了简洁起见,我简化了我的工作。这与最初的答案非常相似,但我修改了Jersey LoggingStream(这是一个您无法访问的内部类),并将登录的能力提高到最大大小

您有一个扩展OutputStream的类,以便可以捕获其中的实体。它将写入您的输出流以及原始输出流

public class MyLoggingStream extends FilterOutputStream
{
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();

public MyLoggingStream(final OutputStream inner)
{
    super(inner);
}

public String getString(final Charset charset)
{
    final byte[] entity = baos.toByteArray();
    return new String(entity, charset);
}

@Override
public void write(final int i) throws IOException
{
    baos.write(i);
    out.write(i);
}
}
然后你有一个过滤器类。对于我的用例来说,能够获取实体并单独记录它是很重要的(为了简单起见,我将它放在下面的println中)。在Jersey的LoggingFilter和LoggingFeature中,实体由拦截器记录,因此您无法捕获它

@Provider
public class MyLoggingClientFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor
{
protected static String HTTPCLIENT_START_TIME = "my-http-starttime";
protected static String HTTPCLIENT_LOG_STREAM = "my-http-logging-stream";

@Context
private ResourceInfo resourceInfo;

public void filter(final ClientRequestContext requestContext) throws IOException
{
    requestContext.setProperty(HTTPCLIENT_START_TIME, System.nanoTime());

    final OutputStream stream = new MyLoggingStream(requestContext.getEntityStream());
    requestContext.setEntityStream(stream);
    requestContext.setProperty(HTTPCLIENT_LOG_STREAM, stream);
}

public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext)
{
    StringBuilder builder = new StringBuilder("--------------------------").append(System.lineSeparator());

    long startTime = (long)requestContext.getProperty(HTTPCLIENT_START_TIME);
    final double duration = (System.nanoTime() - startTime) / 1_000_000.0;
    builder.append("Response Time: ").append(duration);

    if(requestContext.hasEntity())
    {
        final MyLoggingStream stream = (MyLoggingStream)requestContext.getProperty(HTTPCLIENT_LOG_STREAM);
        String body = stream.getString(MessageUtils.getCharset(requestContext.getMediaType()));
        builder.append(System.lineSeparator()).append("Entity: ").append(body);
    }

    builder.append(System.lineSeparator()).append("--------------------------");
    System.out.println(builder.toString());

    requestContext.removeProperty(HTTPCLIENT_START_TIME);
    requestContext.removeProperty(HTTPCLIENT_LOG_STREAM);
}

@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException
{
    // This forces the data to be written to the output stream
    context.proceed();
}

}

这两个问题对您有帮助吗?-[如何使用Jersey获取完整的REST请求正文?][1]-[JAX-RS资源方法中获取原始请求正文][2][1]:[2]:您想在客户端还是服务器端记录它?是否要将日志记录在资源方法内部或之前?是否需要扩展WriterInterceptor并重写aroundWriteTo()?没有WriterInterceptor它似乎工作得很好这似乎根本不起作用。自定义的
OutputStream
从未写入,可能是因为主体已经写入。