我需要使Jersey拒绝内容长度不正确的请求。我正在使用ContainerRequestFilter
过滤器检查内容长度,如下所示:
public class ContentLengthRequiredRequestFilter implements ContainerRequestFilter {
private static Logger LOG = LoggerFactory.getLogger(ContentLengthRequiredRequestFilter.class);
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (requestContext.getMethod() == javax.ws.rs.HttpMethod.POST
|| requestContext.getMethod() == javax.ws.rs.HttpMethod.PUT) {
int givenContentLength = requestContext.getLength();
if (givenContentLength == -1) {
// no content-length given, but it is is required for PUT and POST requests
requestContext.abortWith(Response.status(Response.Status.LENGTH_REQUIRED).entity("No content-length provided.").build());
} else {
// now check if the given content-length is actually correct.
// since I only have a reference to an entity stream, it seems to be that
// reading the entire stream and then resetting it is not a good solution.
// Should I be checking this somewhere else, perhaps somewhere the entity is already available or where I can get the total size of the body without causing the stream to be read twice? Or is there a better way to get the body size here?
}
}
}
}
如您在代码块注释中看到的,我是否应该在其他地方进行检查,也许是该实体已经可用的某个地方,或者可以在不导致两次读取流的情况下获取主体的总大小的地方?还是有一种更好的方法来获得身材?
谢谢!!
最佳答案
如果您不想缓冲传入的实体(输入流),请查看ReaderInterceptor接口。仅在传入请求包含实体(通常为POST,PUT)的情况下才调用此合同的实例。在拦截器中,您几乎可以对实体执行任何操作。一个简单的代码段(并非涵盖所有情况)如下所示:
public class MyInterceptor implements ReaderInterceptor {
@Override
public Object aroundReadFrom(final ReaderInterceptorContext context) throws IOException, WebApplicationException {
final InputStream old = context.getInputStream();
final String first = context.getHeaders().getFirst("Content-Length");
final Long declared = first == null ? -1 : Long.valueOf(first);
context.setInputStream(new InputStream() {
private long length = 0;
private int mark = 0;
@Override
public int read() throws IOException {
final int read = old.read();
readAndCheck(read != -1 ? 1 : 0);
return read;
}
@Override
public int read(final byte[] b) throws IOException {
final int read = old.read(b);
readAndCheck(read != -1 ? read : 0);
return read;
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
final int read = old.read(b, off, len);
readAndCheck(read != -1 ? read : 0);
return read;
}
@Override
public long skip(final long n) throws IOException {
final long skip = old.skip(n);
readAndCheck(skip != -1 ? skip : 0);
return skip;
}
@Override
public int available() throws IOException {
return old.available();
}
@Override
public void close() throws IOException {
old.close();
}
@Override
public synchronized void mark(final int readlimit) {
mark += readlimit;
old.mark(readlimit);
}
@Override
public synchronized void reset() throws IOException {
this.length = 0;
readAndCheck(mark);
old.reset();
}
@Override
public boolean markSupported() {
return old.markSupported();
}
private void readAndCheck(final long read) {
this.length += read;
if (this.length > declared) {
throw new WebApplicationException(
Response.status(Response.Status.LENGTH_REQUIRED)
.entity("No content-length provided.")
.build());
}
}
});
final Object entity = context.proceed();
context.setInputStream(old);
return entity;
}
}
在上面的拦截器中,我设置了自己的输入流,该输入流对从原始输入流读取的字节数进行计数和检查。但是,此实现还取决于基础容器如何处理输入流(即,在读取输入流时是否还检查内容长度)。