Jersey - 在调用 context.proceed() 之前获取拦截器中 OutputStream 的内容
Jersey - Obtain the contents of an OutputStream in an Interceptor before calling context.proceed()
在 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();
}
}
但是,问题是当我最终读取整个流时,我无法将 header 设置为调用 context.proceed 并写入内容(从而启用我可以用它做任何事情)我不能再设置 header.
我的问题简而言之:如何将整个流输出捕获为字节 [],从字节数组计算结果并最终在对计算结果的响应中设置 header?我不想耗尽输出流。
如果您曾经使用过 AOP 框架甚至 CDI 拦截器,那么您将分别使用过 Around-Advice 或 Around-Invoke 的概念。在调用advised/intercepted方法后,可以执行和之前的操作。 context.proceed()
以同样的方式工作;它是方法调用(或者更准确地说是 MessageBodyWriter
正在写)。我们可以在 MessageBodyWriter
完成它的工作之前执行一些操作,调用 proceed()
让 writer 完成它的工作,然后我们可以做更多的工作。
话虽如此,您可以采取以下步骤:
- 坚持
context
的旧 OutputStream
,context.getOutputStream()
- 创建一个
ByteArrayOutputStream
并将其设置为上下文中的 OutputStream
,context.setOutputStream(baos)
- 呼叫
context.proceed()
。这样做是让 MessageBodyWriter
写入 ByteArrayOutputStream
.
- 用
baos.toByteArray()
从 ByteArrayOutputStream
得到 byte[]
- 校验和
byte[]
并设置 header
- 将
byte[]
写到旧的OutputStream
。
- 最后将
context
上的 OutputStream
设置为旧的 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);
}
}
}
在 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();
}
}
但是,问题是当我最终读取整个流时,我无法将 header 设置为调用 context.proceed 并写入内容(从而启用我可以用它做任何事情)我不能再设置 header.
我的问题简而言之:如何将整个流输出捕获为字节 [],从字节数组计算结果并最终在对计算结果的响应中设置 header?我不想耗尽输出流。
如果您曾经使用过 AOP 框架甚至 CDI 拦截器,那么您将分别使用过 Around-Advice 或 Around-Invoke 的概念。在调用advised/intercepted方法后,可以执行和之前的操作。 context.proceed()
以同样的方式工作;它是方法调用(或者更准确地说是 MessageBodyWriter
正在写)。我们可以在 MessageBodyWriter
完成它的工作之前执行一些操作,调用 proceed()
让 writer 完成它的工作,然后我们可以做更多的工作。
话虽如此,您可以采取以下步骤:
- 坚持
context
的旧OutputStream
,context.getOutputStream()
- 创建一个
ByteArrayOutputStream
并将其设置为上下文中的OutputStream
,context.setOutputStream(baos)
- 呼叫
context.proceed()
。这样做是让MessageBodyWriter
写入ByteArrayOutputStream
. - 用
baos.toByteArray()
从 - 校验和
byte[]
并设置 header - 将
byte[]
写到旧的OutputStream
。 - 最后将
context
上的OutputStream
设置为旧的OutputStream
。
ByteArrayOutputStream
得到 byte[]
这是基本实现(已测试并按预期工作)
@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);
}
}
}