我在 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 {}