在Jersey中使用拦截器我可以操作输出,但是,我还想在响应中添加一个Header,该值根据输出结果计算得出。
@Sha256Sum
public class Sha256SumInterceptor implements WriterInterceptor {
public static final String SHA256_HASH_HEADER_NAME = "SHA256-SUM";
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
// Retrieve the OutputStream, read the contents and calculate the hashsum.
// Set the header value in context.
context.proceed();
}
}
然而,问题是当我最终读完整个流时,我无法设置标题,因为调用了context.proceed并写入了内容(从而使我可以用它做任何事情)我可以不再设置标题。
我的问题简单:如何将整个流输出捕获为byte [],从字节数组计算结果,最后在对计算结果的响应中设置标头?我不想耗尽输出流。
答案 0 :(得分:4)
如果您曾经使用过AOP框架甚至是CDI拦截器,那么您将分别使用Around-Advice或Around-Invoke的概念。在调用建议/截获方法之后,您可以在和之前执行操作。 context.proceed()
的工作方式相同;它是方法调用(或者更准确地说是MessageBodyWriter
正在编写它)。我们可以在MessageBodyWriter
完成工作之前执行一些操作,调用proceed()
让作者完成它的工作,然后我们可以做更多的工作。
话虽如此,以下是您可以采取的步骤:
OutputStream
context
中的旧context.getOutputStream()
ByteArrayOutputStream
并将其设置为上下文中的OutputStream
,context.setOutputStream(baos)
context.proceed()
。这样做是MessageBodyWriter
写入ByteArrayOutputStream
。byte[]
ByteArrayOutputStream
获取baos.toByteArray()
byte[]
并设置标题byte[]
写入旧OutputStream
。OutputStream
上的context
设置为旧OutputStream
。这是基本的实现(测试并按预期工作)
@Provider
public class ChecksumInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
OutputStream old = context.getOutputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
context.setOutputStream(buffer);
// let MessageBodyWriter do it's job
context.proceed();
// get bytes
byte[] entity = buffer.toByteArray();
String checksum = ChecksumUtil.createChecksum(entity);
context.getHeaders().putSingle("X-Checksum", checksum);
old.write(entity);
} finally {
context.setOutputStream(old);
}
}
}