获取我的请求的请求正文

时间:2014-03-10 10:36:09

标签: 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

2 个答案:

答案 0 :(得分:2)

您可以尝试为实体包装Outputstream。首先,使用javax.ws.rs.client.ClientRequestFilter将自定义Outputstream添加到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()));
  }

我不确定输出流在哪一点用于序列化数据。它可能是您调用buildPut()的时刻,但更有可能是在访问webclient时即时。

另一种方法是获取底层的HttpClient并在那里注册一些侦听器来获取正文。

答案 1 :(得分:0)

我有类似的问题。我无法使用Jersey LoggingFilter(和2.23中的新LoggingFeature),因为我需要自定义输出。要使用其他选项,您可以看到以下帖子:Jersey: Print the actual request

为简洁起见,我简化了所做的工作。它与原始答案非常相似,但我修改了Jersey LoggingStream(它是一个你无法访问的内部类),并且能够记录到最大尺寸。

您有一个扩展OutputStream的类,因此您可以捕获其中的实体。它将写入您的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();
}

}