【发布时间】:2020-06-12 13:56:20
【问题描述】:
每当我的 rest 应用程序抛出内部错误时,我都想记录导致它失败的确切请求。为此,我创建了一个 ContainerResponseFilter。它检查响应状态是否大于或等于 500。如果是,它会序列化 ContainerRequestContext 并将其持久化到 S3。
@Provider
@ApplicationScoped
public class GlobalContainerResponseFilter implements ContainerResponseFilter {
@Override
public void filter (ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
if (responseContext.getStatus() >= 500) {
ContainerRequestContextSerialiser serialiser = new ContainerRequestContextSerialiser();
// creates a JSON with the URI, headers, form parameters, body of the request, and all the information available on ContainerRequestContext
String json = serialiser.serialise(requestContext);
AwsS3Client client = new AwsS3Client();
client.persist(json, LocalDateTime.now());
}
}
}
我很难处理实体输入流。如果它还没有被读取,我不需要序列化它,因为它不是异常的原因。例如,应用程序可能无法解析查询参数。如果它被读取,我想序列化它,但我不能,因为无法再次读取流。 我的第一个想法是创建一个 ContainerRequestFilter,如下所示:
@Provider
@ApplicationScoped
public class GlobalContainerRequestFilter implements ContainerRequestFilter {
@Override
public void filter (ContainerRequestContext requestContext) {
requestContext.setEntityStream(new InputStreamThatCanBeReadAgain(requestContext.getEntityStream()));
}
public static class InputStreamThatCanBeReadAgain extends InputStream {
private final InputStream source;
private final ByteArrayOutputStream os = new ByteArrayOutputStream();
public InputStreamThatCanBeReadAgain (InputStream source) {
this.source = source;
}
@Override
public int read () throws IOException {
int read = source.read();
os.write(read);
return read;
}
public InputStream getInputStreamToBeReadAgain () {
return new ByteArrayInputStream(os.toByteArray());
}
}
}
然后,在 ContainerResponseFilter 上,我将实体流转换为 InputStreamThatCanBeReadAgain 并获取我需要的数据。但这会为每个请求复制内存中的实体信息,即使是那些不会产生内部错误的请求,这应该是其中的绝大多数。
那么,还有其他方法可以完成这项工作吗?我想实体信息已经存在于某个地方,我只需要获取它的字节。
【问题讨论】: