spring boot 使用Jetty 容器开启HTTP压缩,只有GET请求生效问题

application.yml中配置HTTP压缩

server:
  port: 9000
  compression:
    enabled: true
    mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain

发现只有GET请求被压缩
从项目启动的main 方法到run方法再到refresh,最后在EmbeddedWebApplicationContext 类中onRefresh方法,找到 创建web容器的地方

@Override
    protected void onRefresh() {
        super.onRefresh();
        try {
            createEmbeddedServletContainer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start embedded container",
                    ex);
        }
    }

createEmbeddedServletContainer方法会获取项目中指定容器的工厂类EmbeddedServletContainerFactory,并利用EmbeddedServletContainerFactory创建容器,详见代码:

private void createEmbeddedServletContainer() {
        EmbeddedServletContainer localContainer = this.embeddedServletContainer;
        ServletContext localServletContext = getServletContext();
        if (localContainer == null && localServletContext == null) {
            EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
            this.embeddedServletContainer = containerFactory
                    .getEmbeddedServletContainer(getSelfInitializer());
        }
        else if (localServletContext != null) {
            try {
                getSelfInitializer().onStartup(localServletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                        ex);
            }
        }
        initPropertySources();
    }

在创建容器时,会根据application.yml中的配置设置GzipHandler

    private Handler addHandlerWrappers(Handler handler) {
        if (getCompression() != null && getCompression().getEnabled()) {
            handler = applyWrapper(handler, createGzipHandler());
        }
        if (StringUtils.hasText(getServerHeader())) {
            handler = applyWrapper(handler, new ServerHeaderHandler(getServerHeader()));
        }
        return handler;
    }

但是在创建GzipHandler时只是设置了压缩临界值和需要压缩的类型

public HandlerWrapper createGzipHandler(Compression compression) {
            GzipHandler handler = new GzipHandler();
            handler.setMinGzipSize(compression.getMinResponseSize());
            handler.setIncludedMimeTypes(compression.getMimeTypes());
            if (compression.getExcludedUserAgents() != null) {
                handler.setExcludedAgentPatterns(compression.getExcludedUserAgents());
            }
            return handler;
        }

而GizpHandler默认支持的只有GET类型

public GzipHandler()
    {
        _methods.include(HttpMethod.GET.asString());
        for (String type:MimeTypes.getKnownMimeTypes())
        {
            if ("image/svg+xml".equals(type))
                _paths.exclude("*.svgz");
            else if (type.startsWith("image/")||
                type.startsWith("audio/")||
                type.startsWith("video/"))
                _mimeTypes.exclude(type);
        }
        _mimeTypes.exclude("application/compress");
        _mimeTypes.exclude("application/zip");
        _mimeTypes.exclude("application/gzip");
        _mimeTypes.exclude("application/bzip2");
        _mimeTypes.exclude("application/brotli");
        _mimeTypes.exclude("application/x-xz");
        _mimeTypes.exclude("application/x-rar-compressed");

        if (LOG.isDebugEnabled())
            LOG.debug("{} mime types {}",this,_mimeTypes);
        
        _agentPatterns.exclude(".*MSIE 6.0.*");
    }

综上,只需在启动时增加容器中GzipHandler的支持的请求就行

解决方法

在使用Jetty容器的项目中添加此类

@Component
@Order(1)
class HttpGzipConfig : ApplicationContextAware, ApplicationRunner {
    override fun run(args: ApplicationArguments?) {
        (((applicationContext as EmbeddedWebApplicationContext).embeddedServletContainer as JettyEmbeddedServletContainer).server.handler as GzipHandler).addIncludedMethods(HttpMethod.POST.asString())
    }

    @Throws(BeansException::class)
    override fun setApplicationContext(arg0: ApplicationContext) {
        if (applicationContext == null) {
            applicationContext = arg0
        }
    }

    companion object {
        var applicationContext: ApplicationContext? = null
    }

}

你可能感兴趣的:(spring boot 使用Jetty 容器开启HTTP压缩,只有GET请求生效问题)