Jetty uber jar 上的 GzipHandler

GzipHandler on Jetty uber jar

我用嵌入式码头服务器创建了 uber jar(我更新到 9.4.20.v20190813)。胖应用包括两部分:静态前端和api后端。从 jetty server 9.1 multiple embeded ports and application in same server instance 复制的代码框架。我想在两个网络应用程序上添加 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, 一些资源 return 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.run(ChannelEndPoint.java:117)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)

我的问题:favicon.ico的mime-type没有包含在GzipHandler中,为什么GzipHandler会处理它? favicon.ico 位于静态资源 Web 应用程序根目录中(与 index.html 相同级别)。

如何正确应用 gziphandler?谢谢!

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

编辑:

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

Jetty 9.1 已停产。

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

您的代码有效,as-is,只需升级到受支持的 Jetty 版本即可。

我使用 Jetty 9.4.20.v20190813 进行了测试,它按设计运行。

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

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

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