0

我在 Jetty 上使用 Jersey2 编写了一个基本的 REST 服务器,以测试 HTTP 块传输编码和 gzip 内容编码。但是,我发现实施 WriterInceptor 以应用 GZIPOutputStream 进行 gzip 编码的推荐方法会导致服务器阻塞,而不是通过 gzip 块发送。我相信这是 GZIPOutputStream 等待它自己的缓冲区填满,所以我尝试在 WriterInterceptor 中覆盖 write() 方法以在每次写入后强制执行 flush() (因为我的服务器总是一次写入一个块)但这使得没有不同。有没有办法在写入发生时强制刷新?

应用程序.java

public class App
{

    public static int lineCount=0;

    public static void main( String[] args ) {

        System.out.println( "Hello World!" );

        ResourceConfig config = new ResourceConfig();
        config.packages("com.example.mockAPIjava");
        ServletHolder servlet = new ServletHolder(new ServletContainer(config));

        EncodingFilter.enableFor(config, GZipEncoder.class);

        Server server = new Server(2222);
        ServletContextHandler context = new ServletContextHandler(server, "/*");
        context.addServlet(servlet, "/*");


        try {
            server.start();
            server.join();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            server.destroy();
        }
    }
}

GZIPWriterInterceptor.java

@Provider
@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {

    @Override
    public void aroundWriteTo(WriterInterceptorContext context)
            throws IOException, WebApplicationException {

        MultivaluedMap<String,Object> headers = context.getHeaders();
        headers.add("Content-Encoding", "gzip");

        final OutputStream outputStream = context.getOutputStream();
        context.setOutputStream(new GZIPOutputStream(outputStream) {
            @Override
            public void write(final int b) throws IOException {
                out.write(b);
                out.flush();
            }

            @Override
            public void write(final byte[] b) throws IOException {
                out.write(b);
                out.flush();
            }

            @Override
            public void write(final byte[] b, final int off, final int len) throws IOException {
                out.write(b, off, len);
                out.flush();
            }
        });
        context.proceed();
    }
}

资源.java

@Path("stream")
public class Resource {
    @GET
    @Path("test")
    @Compress
    @Produces(MediaType.APPLICATION_JSON)
    public ChunkedOutput<String> helloWorld(@Context HttpHeaders header, @Context HttpServletResponse response) {
        final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class, "\r\n");

        new Thread() {
            public void run() {
                BufferedReader br = null;

                try {
                    String chunk;

                    // open file for reading
                    File file = new File("/tmp/stream.txt");
                    FileReader fr = new FileReader(file);
                    br = new BufferedReader(fr);

                    while ((chunk = getNextString(br)) != null) {
                        // write a chunk every second
                        output.write(chunk);

                        try {
                            Thread.sleep(1 * 1000);
                        } catch(InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                    }

                } catch (Exception e) {
                    // IOException thrown when writing the
                    // chunks of response: should be handled
                    e.printStackTrace();
                } finally {
                    try {        
                        output.close();
                        // simplified: IOException thrown from
                        // this close() should be handled here...
                        if (br!=null) { br.close(); }
                    } catch (IOException e1){
                        e1.printStackTrace();
                    }
                }
            }
        }.start();

        // the output will be probably returned even before
        // a first chunk is written by the new thread
        return output;
    }


    private String getNextString(BufferedReader br) throws IOException, ParseException {
        App.lineCount++;
        return br.readLine();;
    }
}

压缩.java

//@Compress annotation is the name binding annotation for the GZIPWriterInterceptor
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {}
4

1 回答 1

0

通过覆盖 的write方法GZIPOutputStream,您刚刚停止了 gzip 压缩!

public void write(final int b) throws IOException {
    out.write(b);
    out.flush();
}

因为您已将其覆盖为调用super.write(您应该这样做),而是out.write直接发送到未压缩的上下文 OutputStream。

据推测,接收方期待 gzip 数据并没有收到它,这可能会导致各种错误行为。

更改代码以调用super.writeflush

public void write(final int b) throws IOException {
    super.write(b);
    flush();
}

等等

于 2017-02-26T09:09:52.223 回答