Jetty uber jar上的GzipHandler

时间:2019-08-29 16:21:47

标签: jetty embedded-jetty

我创建了带有嵌入式码头服务器的uber jar(我更新为9.4.20.v20190813)。胖应用程序包括两个部分:静态前端和api后端。从jetty server 9.1 multiple embeded ports and application in same server instance复制的代码框架。我想在两个Web应用程序上都添加GzipHandler

public class Main
{
    public static void main(String[] args)
    {
        Server server = new Server();

        ServerConnector connectorA = new ServerConnector(server);
        connectorA.setPort(8080);
        connectorA.setName("connA"); // connector name A (static web app)
        ServerConnector connectorB = new ServerConnector(server);
        connectorB.setPort(9090);
        connectorB.setName("connB"); // connector name B (api app)

        server.addConnector(connectorA);
        server.addConnector(connectorB);

        // Basic handler collection
        HandlerCollection contexts = new HandlerCollection();
        server.setHandler(contexts);

        // WebApp A
        WebAppContext appA = new WebAppContext();
        appA.setContextPath("/a");
        appA.setWar("./webapps/webapp-a.war");
        appA.setVirtualHosts(new String[]{"@connA"}); // connector name A
        contexts.addHandler(appA);

        // WebApp B
        WebAppContext appB = new WebAppContext();
        appB.setContextPath("/b");
        appB.setWar("./webapps/webapp-b.war");
        appB.setVirtualHosts(new String[]{"@connB"}); // connector name B
        contexts.addHandler(appB);

    GzipHandler gzipHandler = new GzipHandler();
    gzipHandler.setIncludedMethods("POST", "GET");
    gzipHandler.setIncludedMimeTypes("text/html", "text/plain", "text/xml", "text/css", "application/javascript",
                                     "text/javascript", "application/json");
    gzipHandler.setInflateBufferSize(2048);
    gzipHandler.setMinGzipSize(2048);

        contexts.addHandler(gzipHandler);

        try
        {
            server.start(); // start server thread
            server.join(); // wait for server thread to end
        }
        catch (Throwable t)
        {
            t.printStackTrace(System.err);
        }
    }
}

当我访问http://localhost:8080时,一些资源返回Status Code: 206 Partial Content,服务器抛出异常:

17:16:31.447 [qtp60830820-16] WARN  org.eclipse.jetty.server.HttpChannel - /favicon.ico
java.lang.NullPointerException: null
    at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:725)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.Server.handle(Server.java:502)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)

我的问题:favicon.ico的mime类型不包含在GzipHandler中,为什么GzipHandler处理它?并且favicon.ico在静态资源Web应用程序的根目录中(与index.html处于同一级别)。

如何正确应用gziphandler?谢谢!

顺便说一句:gzip过滤器工作正常

编辑:

  1. 我将码头版本从9.4.12.v20180830升级到9.4.20.v20190813
  2. 我在GzipHandler上添加了更多设置

1 个答案:

答案 0 :(得分:1)

Jetty 9.1是EOL(寿命终止)。

https://www.eclipse.org/jetty/documentation/current/what-jetty-version.html

您的代码按原样工作,只需升级到受支持的Jetty版本。

我在Jetty 9.4.20.v20190813上进行了测试,并且按设计工作。

状态代码:206 Partial Content是预期的状态响应代码,当响应包含部分范围数据时,仅当请求包含Range:标头时才产生。

您的代码具有一个如下所示的处理程序树..

Server.setHandler
 \- HandlerCollection
     \- WebAppContext ("/a")
     \- WebAppContext ("/b")
     \- GzipHandler

在末尾使用GzipHandler将使GzipHandler适用于与上下文"/a""/b"(这是合法配置)不匹配的请求可能不是您想要的。

自从您提到favicon.ico以来,这通常是一个根请求,既不匹配"/a"也不匹配"/b",因此我们只能假定您想要的是这个。

但是,您实际上并没有说您想将GzipHandler应用于WebAppContext,所以我只是假设这是您真正想要实现的目标。

如果是这种情况,那么在输入GzipHandler之前,我们需要WebAppContext做它需要做的事情。

我们想要一个看起来像这样的处理程序树...

Server.setHandler
 \- HandlerList
     \- GzipHandler
     |   \- ContextHandlerCollection
     |       \- WebAppContext ("/a")
     |       \- WebAppContext ("/b")
     \- DefaultHandler

将是为所有上下文配置的单个GzipHandler

粗略的代码看起来像这样...

HandlerList handlers = new HandlerList();
server.setHandler(handlers);

WebAppContext appA = new WebAppContext();
appA.setContext("/a");
WebAppContext appB = new WebAppContext();
appB.setContextPath("/b");

ContextHandlerCollection contexts = new ContextHandlerCollection(appA, appB);

GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setHandler(contexts);

handlers.addHandler(gzipHandler);
handlers.addHandler(new DefaultHandler());

但是每个WebApp也可以具有唯一的GzipHandler

看起来像这样...

Server.setHandler
 \- HandlerList
     \- ContextHandlerCollection
     |   \- WebAppContext ("/a")
     |       \- GzipHandler (instance / config A)
     |   \- WebAppContext ("/b")
     |       \- GzipHandler (instance / config B)
     \- DefaultHandler

或这样...

Server.setHandler
 \- HandlerList
     \- GzipHandler (instance / config A)
     |   \- WebAppContext ("/a")
     \- GzipHandler (instance / config B)
     |   \- WebAppContext ("/b")
     \- DefaultHandler