如何获得我将要做的实际请求?
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
答案 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();
}
}