http压缩相关类Compression.java

package org.springframework.boot.web.server;

import org.springframework.util.unit.DataSize;

/**
 * Simple server-independent abstraction for compression configuration.
 *
 * @author Ivan Sopov
 * @author Andy Wilkinson
 * @author Stephane Nicoll
 * @since 2.0.0
 */
public class Compression {

    private boolean enabled = false;

    private String[] mimeTypes = new String[] { "text/html", "text/xml", "text/plain", "text/css", "text/javascript",
            "application/javascript", "application/json", "application/xml" };

    private String[] excludedUserAgents = null;

    private DataSize minResponseSize = DataSize.ofKilobytes(2);

    /**
     * Return whether response compression is enabled.
     * @return {@code true} if response compression is enabled
     */
    public boolean getEnabled() {
        return this.enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
     * Return the MIME types that should be compressed.
     * @return the MIME types that should be compressed
     */
    public String[] getMimeTypes() {
        return this.mimeTypes;
    }

    public void setMimeTypes(String[] mimeTypes) {
        this.mimeTypes = mimeTypes;
    }

    public String[] getExcludedUserAgents() {
        return this.excludedUserAgents;
    }

    public void setExcludedUserAgents(String[] excludedUserAgents) {
        this.excludedUserAgents = excludedUserAgents;
    }

    /**
     * Return the minimum "Content-Length" value that is required for compression to be
     * performed.
     * @return the minimum content size in bytes that is required for compression
     */
    public DataSize getMinResponseSize() {
        return this.minResponseSize;
    }

    public void setMinResponseSize(DataSize minSize) {
        this.minResponseSize = minSize;
    }

}

通过以上代码了解

1、从Spring 2.x开始就支持http响应流压缩

2、默认不开启压缩

3、默认压缩阈值2K,当响应流字节达到2K才压缩

4、支持过滤特定类型的User-Agent

5、默认压缩文件类型

"text/html", "text/xml", "text/plain", "text/css", "text/javascript",
            "application/javascript", "application/json", "application/xml" 

 

解决方案

在application.properties或者application.yml配置相关属性

server.compression.enabled=true

server.compression.min-response-size=1024 #响应流达到1024字节再压缩

application.yml

server:
    compression:
        enabled: true
        min-response-size: 1024

 

参考:https://frontbackend.com/spring/how-to-enable-gzip-compression-in-spring-boot

关于排除自定义的User-Agent

笔者追踪源代码,找到了相关代码片段

Tomcat

org.springframework.boot.web.embedded.tomcat.CompressionConnectorCustomizer
package org.springframework.boot.web.embedded.tomcat;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.UpgradeProtocol;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.coyote.http2.Http2Protocol;

import org.springframework.boot.web.server.Compression;
import org.springframework.util.StringUtils;

/**
 * {@link TomcatConnectorCustomizer} that configures compression support on the given
 * Connector.
 *
 * @author Brian Clozel
 */
class CompressionConnectorCustomizer implements TomcatConnectorCustomizer {

    private final Compression compression;

    CompressionConnectorCustomizer(Compression compression) {
        this.compression = compression;
    }

    @Override
    public void customize(Connector connector) {
        if (this.compression != null && this.compression.getEnabled()) {
            ProtocolHandler handler = connector.getProtocolHandler();
            if (handler instanceof AbstractHttp11Protocol) {
                customize((AbstractHttp11Protocol<?>) handler);
            }
            for (UpgradeProtocol upgradeProtocol : connector.findUpgradeProtocols()) {
                if (upgradeProtocol instanceof Http2Protocol) {
                    customize((Http2Protocol) upgradeProtocol);
                }
            }
        }
    }

    private void customize(Http2Protocol protocol) {
        Compression compression = this.compression;
        protocol.setCompression("on");
        protocol.setCompressionMinSize(getMinResponseSize(compression));
        protocol.setCompressibleMimeType(getMimeTypes(compression));
        if (this.compression.getExcludedUserAgents() != null) {
            protocol.setNoCompressionUserAgents(getExcludedUserAgents());
        }
    }

    private void customize(AbstractHttp11Protocol<?> protocol) {
        Compression compression = this.compression;
        protocol.setCompression("on");
        protocol.setCompressionMinSize(getMinResponseSize(compression));
        protocol.setCompressibleMimeType(getMimeTypes(compression));
        if (this.compression.getExcludedUserAgents() != null) {
            protocol.setNoCompressionUserAgents(getExcludedUserAgents());
        }
    }

    private int getMinResponseSize(Compression compression) {
        return (int) compression.getMinResponseSize().toBytes();
    }

    private String getMimeTypes(Compression compression) {
        return StringUtils.arrayToCommaDelimitedString(compression.getMimeTypes());
    }

    private String getExcludedUserAgents() {
        return StringUtils.arrayToCommaDelimitedString(this.compression.getExcludedUserAgents());
    }

}

tomcat的做法是拿到excludedUserAgent然后根据逗号进行分割数组,相关代码如下

    /**
     * Convert a {@code String} array into a comma delimited {@code String}
     * (i.e., CSV).
     * <p>Useful for {@code toString()} implementations.
     * @param arr the array to display (potentially {@code null} or empty)
     * @return the delimited {@code String}
     */
    public static String arrayToCommaDelimitedString(@Nullable Object[] arr) {
        return arrayToDelimitedString(arr, ",");
    }

跟随代码一路往下看,找到(说明支持正则表达式匹配)

 public void setNoCompressionUserAgents(String noCompressionUserAgents) {
        if (noCompressionUserAgents == null || noCompressionUserAgents.length() == 0) {
            this.noCompressionUserAgents = null;
        } else {
            this.noCompressionUserAgents =
                Pattern.compile(noCompressionUserAgents);
        }
    }

undertow

笔者用的是undertow,相关代码

org.springframework.boot.web.embedded.undertow.CompressionHttpHandlerFactory
相关代码
    private static Predicate[] getCompressionPredicates(Compression compression) {
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(new MaxSizePredicate((int) compression.getMinResponseSize().toBytes()));
        predicates.add(new CompressibleMimeTypePredicate(compression.getMimeTypes()));
        if (compression.getExcludedUserAgents() != null) {
            for (String agent : compression.getExcludedUserAgents()) {
                RequestHeaderAttribute agentHeader = new RequestHeaderAttribute(new HttpString(HttpHeaders.USER_AGENT));
                predicates.add(Predicates.not(Predicates.regex(agentHeader, agent)));
            }
        }
        return predicates.toArray(new Predicate[0]);
    }

undertow这里不拐弯抹角,直接就能看到,支持正则表达式

posted on 2021-01-29 12:37  你不知道的浪漫  阅读(1068)  评论(0编辑  收藏  举报