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
}
}
网友评论