Sử dụng nén GZIP với Spring Boot / MVC / JavaConfig với RESTful


95

Chúng tôi sử dụng Spring Boot / MVC với java-config dựa trên chú thích cho một loạt RESTfuldịch vụ và chúng tôi muốn bật tính HTTP GZIPnăng nén luồng một cách có chọn lọc trên một số phản hồi API.

Tôi biết tôi có thể thực hiện việc này theo cách thủ công trong bộ điều khiển của mình và a byte[] @ResponseBody, tuy nhiên chúng tôi muốn dựa vào cơ sở hạ tầng SpringMVC (bộ lọc / v.v.) và để nó tự động thực hiện chuyển đổi và nén JSON (tức là phương thức trả về một POJO).

Làm cách nào để kích hoạt tính năng nén GZIP trong phiên bản ResponseBody hoặc Tomcat nhúng và theo cách chúng tôi có thể chỉ nén một số phản hồi có chọn lọc?

Cảm ơn!

Tái bút: Chúng tôi hiện không có bất kỳ cấu hình dựa trên XML nào.


Bạn nên kiểm tra GzipFilter .
khoảng

2
không sử dụng HTTP nén với HTTPS trừ khi bạn biết những gì bạn đang làm
Neil McGuigan

Câu trả lời:


188

Phần còn lại của những câu trả lời này đã lỗi thời và / hoặc quá phức tạp đối với thứ gì đó phải là IMO đơn giản (gzip đã tồn tại được bao lâu rồi? Lâu hơn Java ...) Từ tài liệu:

Trong ứng dụng.properties 1.3+

# 🗜️🗜️🗜️
server.compression.enabled=true
# opt in to content types
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
# not worth the CPU cycles at some point, probably
server.compression.min-response-size=10240 

Trong ứng dụng.properties 1.2.2 - <1.3

server.tomcat.compression=on
server.tomcat.compressableMimeTypes=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css

Cũ hơn 1.2.2:

@Component
public class TomcatCustomizer implements TomcatConnectorCustomizer {

  @Override
  public void customize(Connector connector) {
    connector.setProperty("compression", "on");
    // Add json and xml mime types, as they're not in the mimetype list by default
    connector.setProperty("compressableMimeType", "text/html,text/xml,text/plain,application/json,application/xml");
  }
}

Cũng lưu ý rằng điều này CHỈ hoạt động nếu bạn đang chạy tomcat được nhúng:

Nếu bạn định triển khai cho tomcat không nhúng, bạn sẽ phải kích hoạt nó trong server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

Ghi chú Sản xuất IRL:

Ngoài ra, để tránh tất cả những điều này, hãy xem xét sử dụng thiết lập proxy / bộ cân bằng tải trước Tomcat với nginx và / hoặc haproxy hoặc tương tự vì nó sẽ xử lý tài sản tĩnh và gzip NHIỀU hiệu quả và dễ dàng hơn so với mô hình phân luồng của Java / Tomcat.

Bạn không muốn ném 'con mèo vào bồn tắm vì nó đang bận nén công cụ thay vì phục vụ yêu cầu (hoặc nhiều khả năng quay chuỗi / ăn CPU / heap ngồi chờ IO cơ sở dữ liệu xảy ra trong khi chạy hóa đơn AWS của bạn tại sao Java / Tomcat truyền thống có thể không phải là một ý tưởng hay khi bắt đầu tùy thuộc vào những gì bạn đang làm nhưng tôi lạc đề ...)

refs: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#how-to-enable-http-response-compression

https://github.com/spring-projects/spring-boot/issues/2031


Cách tiếp cận của bạn đối với các phiên bản cũ hơn 1.2.2 sẽ không hoạt động vì Spring Boot không tìm kiếm các TomcatConnectorCustomizerphiên bản trong ngữ cảnh ứng dụng; họ phải được đăng ký theo chương trìnhTomcatEmbeddedServletContainerFactory
Andy Wilkinson

Cảm ơn cho những người đứng đầu lên. Tôi đã từ bỏ điều này vì có vẻ như khởi động static / dynamic / tomcat / vs vẫn là một vấn đề. Đây là cách khó hơn nó phải được ... Nginx proxy ngược FTW!
John Culviner

3
Trong SpringBoot, các thuộc tính mới là server.compression.enabled = true và server.compression.mime-
styles

2
Nếu khởi động vào mùa xuân, chúng ta có nhiều bộ điều khiển nghỉ, tất cả đều trả về phản hồi JSON. Chúng ta có thể áp dụng một cách chọn lọc mã zip trên một số bộ điều khiển không?

3
Bạn cũng nên đề cập đến kích thước phản hồi tối thiểu để nén (ví dụ: 10KB), nếu không nó sẽ trở thành chi phí cho máy chủ để nén mọi yêu cầu (ví dụ: 0,5KB). server.compression.min-response-size=10240
UsamaAmjad


12

Về cơ bản, đây là giải pháp giống như @ andy-wilkinson đã cung cấp, nhưng kể từ Spring Boot 1.0, phương thức tùy chỉnh (...) có tham số ConfigurableEmbeddedServletContainer .

Một điều đó là đáng nhắc đến là Tomcat chỉ nén các loại nội dung của text/html, text/xmltext/plaintheo mặc định. Dưới đây là một ví dụ cũng hỗ trợ nén application/json:

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer servletContainer) {
            ((TomcatEmbeddedServletContainerFactory) servletContainer).addConnectorCustomizers(
                    new TomcatConnectorCustomizer() {
                        @Override
                        public void customize(Connector connector) {
                            AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                            httpProtocol.setCompression("on");
                            httpProtocol.setCompressionMinSize(256);
                            String mimeTypes = httpProtocol.getCompressableMimeTypes();
                            String mimeTypesWithJson = mimeTypes + "," + MediaType.APPLICATION_JSON_VALUE;
                            httpProtocol.setCompressableMimeTypes(mimeTypesWithJson);
                        }
                    }
            );
        }
    };
}

Tôi đã thử thêm cái này vào Cấu hình Java của mình và thấy rằng nén dường như không hoạt động. Tôi đang sử dụng Spring Boot với Tomcat làm vùng chứa được nhúng và tự hỏi liệu có bất kỳ thứ bổ sung nào tôi cần đặt ngoài cấu hình này không?
Michael Coxon

2
Hãy thử kiểm tra bằng cách xác định Accept-Encoding: gzip,deflatetiêu đề, nếu bạn đang sử dụng curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev

9

Spring Boot 1.4 Sử dụng cái này cho tất cả các nén Javascript HTML Json.

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

Làm cách nào để xác minh việc nén này?
Bhargav

@Bhargav Xem tiêu đề phản hồi của phản hồi api của bạn. Nó phải chứa tiêu đề Content-Encoding:gzip
Sumit Jha


6

Bật GZip trong Tomcat không hoạt động trong Dự án khởi động mùa xuân của tôi. Tôi đã sử dụng CompressionFilter được tìm thấy ở đây .

@Bean
public Filter compressingFilter() {
    CompressingFilter compressingFilter = new CompressingFilter();
    return compressingFilter;
}

@ user1127860 tnx cái này hoạt động nhưng vẫn phải định cấu hình Bộ lọc này hơn nữa? Tôi sử dụng khởi động mùa xuân và dường như không thể thêm các tham số init như hướng dẫn sử dụng đã nói trong web.xml
Mùa xuân

5

Để bật tính năng nén GZIP, bạn cần sửa đổi cấu hình của phiên bản Tomcat được nhúng. Để làm như vậy, bạn khai báo một EmbeddedServletContainerCustomizerbean trong cấu hình Java của mình và sau đó đăng kýTomcatConnectorCustomizer với nó.

Ví dụ:

@Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainerFactory factory) {
            ((TomcatEmbeddedServletContainerFactory) factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
                @Override
                public void customize(Connector connector) {
                    AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                    httpProtocol.setCompression("on");
                    httpProtocol.setCompressionMinSize(64);
                }
            });
        }
    };
}

Xem tài liệu Tomcat để biết thêm chi tiết về các tùy chọn cấu hình nén khác nhau có sẵn.

Bạn nói rằng bạn muốn bật tính năng nén có chọn lọc. Tùy thuộc vào tiêu chí lựa chọn của bạn, thì cách tiếp cận trên có thể là đủ. Nó cho phép bạn kiểm soát việc nén bởi tác nhân người dùng của yêu cầu, kích thước của phản hồi và kiểu mime của phản hồi.

Nếu điều này không đáp ứng nhu cầu của bạn thì tôi tin rằng bạn sẽ phải thực hiện nén trong bộ điều khiển của mình và trả lại phản hồi byte [] với tiêu đề mã hóa nội dung gzip.


1
Sự khác biệt giữa câu trả lời của bạn cho tùy chọn đặt cài đặt trên application.properties là gì? server.compression.enabled = true server.compression.mime-styles = application / json, application / xml, text / html, text / xml, text / trơn, application / javascript, text / css
lukass77 22/02/18

Câu trả lời này đã được viết trước khi có cấu hình nén dựa trên thuộc tính. Chúng tương đương nhau, nhưng cách tiếp cận dựa trên thuộc tính dễ dàng hơn nên tôi khuyên bạn nên sử dụng cách đó.
Andy Wilkinson

chỉ muốn chia sẻ rằng trong trường hợp của tôi, tomcat đứng sau trình cân bằng tải lấy https và từ khóa yêu cầu đến tomcat dưới dạng http., khi tôi sử dụng ứng dụng.properties giải pháp phản hồi không phải là gzip nhưng khi tôi sử dụng giải pháp cấu hình lập trình trên trình kết nối, tôi nhận được phản hồi gzip với https yêu cầu LB
lukass77 23/02

một câu hỏi khác trong trường hợp tôi sử dụng giải pháp application.properties .. và xác định thêm 2 đầu nối trên cổng 8081 và 8082 .. tính năng nén có ứng dụng cho tất cả các đầu nối hình nón hay chỉ cho đầu nối 8080?
lukass77

Tôi xác nhận điều này, tính năng biên dịch chỉ áp dụng trên cổng 8080, ngay cả khi bạn mở nhiều trình kết nối hơn .., tôi nghĩ lỗi sẽ được mở trên này để khởi động mùa xuân ?? .., vì vậy giải pháp duy nhất cho tôi là cấu hình có lập trình cho mỗi trình kết nối, not application.properties
lukass77 23/02

0

Tôi đã gặp vấn đề tương tự với dự án Spring Boot + Spring Data của mình khi gọi đến a @RepositoryRestResource.

Vấn đề là kiểu MIME được trả về; đó là application/hal+json. Thêm nó vào server.compression.mime-typestài sản đã giải quyết vấn đề này cho tôi.

Hy vọng điều này sẽ giúp ích cho người khác!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.