spring/springboot/springmvc啟用GZIP壓縮


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這里不拐彎抹角,直接就能看到,支持正則表達式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM