我需要使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;
    }
}


在上面的拦截器中,我设置了自己的输入流,该输入流对从原始输入流读取的字节数进行计数和检查。但是,此实现还取决于基础容器如何处理输入流(即,在读取输入流时是否还检查内容长度)。

10-08 12:20