ใช้การบีบอัด GZIP กับ Spring Boot / MVC / JavaConfig พร้อม RESTful


98

เราใช้ Spring Boot / MVC กับ java-config ที่ใช้คำอธิบายประกอบสำหรับชุดRESTfulบริการต่างๆและเราต้องการเปิดใช้งานการHTTP GZIPบีบอัดสตรีมแบบเลือกในการตอบสนอง API บางรายการ

ฉันรู้ว่าฉันสามารถทำสิ่งนี้ได้ด้วยตนเองในคอนโทรลเลอร์และ a byte[] @ResponseBodyอย่างไรก็ตามเราต้องการพึ่งพาโครงสร้างพื้นฐาน SpringMVC (ตัวกรอง / ฯลฯ ) และให้มันทำการแปลงและบีบอัด JSON โดยอัตโนมัติ (เช่นวิธีการส่งคืน POJO)

ฉันจะเปิดใช้งานการบีบอัด GZIP ในอินสแตนซ์ ResponseBody หรืออินสแตนซ์ Tomcat แบบฝังได้อย่างไรและเราจะบีบอัดเฉพาะการตอบสนองบางส่วนได้อย่างไร

ขอบคุณ!

PS: ขณะนี้เราไม่มีการกำหนดค่าตาม XML


คุณควรตรวจสอบGzipFilter
ประมาณ

2
อย่าใช้การบีบอัด HTTP กับ HTTPS เว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่
Neil McGuigan

คำตอบ:


192

คำตอบที่เหลือเหล่านี้ล้าสมัยและ / หรือด้านบนซับซ้อนสำหรับบางสิ่งที่ควรเป็น IMO ง่ายๆ (ตอนนี้ gzip อยู่มานานแค่ไหนแล้วนานกว่า Java ... ) จากเอกสาร:

ใน application.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 

ใน application.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

เก่ากว่า 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");
  }
}

โปรดทราบว่าสิ่งนี้จะใช้ได้เฉพาะเมื่อคุณใช้งาน tomcat แบบฝัง

หากคุณวางแผนที่จะปรับใช้กับ tomcat ที่ไม่ได้ฝังไว้คุณจะต้องเปิดใช้งานใน server.xml http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Standard_Implementation

หมายเหตุการผลิต IRL:

นอกจากนี้เพื่อหลีกเลี่ยงสิ่งเหล่านี้ทั้งหมดให้พิจารณาใช้การตั้งค่าพร็อกซี / ตัวโหลดบาลานเซอร์ที่ด้านหน้าของ Tomcat ด้วยnginxและ / หรือhaproxyหรือที่คล้ายกันเนื่องจากจะจัดการกับสินทรัพย์แบบคงที่และ gzip ได้อย่างมีประสิทธิภาพและง่ายดายกว่ารุ่นเธรดของ Java / Tomcat

คุณไม่ต้องการโยน 'cat ลงในอ่างเพราะมันยุ่งอยู่กับการบีบอัดสิ่งต่างๆแทนที่จะให้บริการตามคำขอ (หรือมีแนวโน้มที่จะปั่นกระทู้ / กิน CPU / heap นั่งรอให้ฐานข้อมูล IO เกิดขึ้นในขณะที่เรียกเก็บเงิน AWS ของคุณซึ่งก็คือ ทำไม Java / Tomcat แบบดั้งเดิมอาจไม่ใช่ความคิดที่ดีที่จะเริ่มต้นขึ้นอยู่กับว่าคุณกำลังทำอะไรอยู่ แต่ฉันพูดนอกเรื่อง ... )

อ้างอิง: 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


แนวทางของคุณสำหรับเวอร์ชันที่เก่ากว่า 1.2.2 จะใช้ไม่ได้เนื่องจาก Spring Boot ไม่มองหาTomcatConnectorCustomizerอินสแตนซ์ในบริบทของแอปพลิเคชัน ต้องลงทะเบียนแบบเป็นโปรแกรมกับTomcatEmbeddedServletContainerFactory
Andy Wilkinson

ขอบคุณสำหรับหัวขึ้น. ฉันยอมแพ้กับสิ่งนี้เนื่องจากดูเหมือนว่าการบูตแบบคงที่ / ไดนามิก / tomcat / vs ยังคงเป็นปัญหาอยู่ นี่เป็นวิธีที่ยากกว่าที่ควรจะเป็น ... Nginx reverse proxy FTW!
John Culviner

3
ใน SpringBoot คุณสมบัติใหม่คือ server.compression.enabled = true และ server.compression.mime-types = XXX, YYY github.com/spring-projects/spring-boot/wiki/…
blacelle

2
หากสำหรับสปริงบูตเรามีตัวควบคุมส่วนที่เหลือหลายตัวที่ส่งคืนการตอบสนอง JSON ทั้งหมด เราสามารถเลือกใช้ซิปกับคอนโทรลเลอร์บางตัวได้หรือไม่?

3
คุณควรระบุขนาดการตอบกลับขั้นต่ำสำหรับการบีบอัด (เช่น 10KB) มิฉะนั้นจะกลายเป็นค่าใช้จ่ายสำหรับเซิร์ฟเวอร์ที่จะบีบอัดทุกคำขอ (เช่น 0.5KB) server.compression.min-response-size=10240
UsamaAmjad

13

ในเวอร์ชันล่าสุดในapplication.ymlconfig:

---

spring:
  profiles: dev

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

---

รายงานข้อบกพร่องที่เกี่ยวข้องและแก้ไขจุดที่เปลี่ยนแปลงคือgithub.com/spring-projects/spring-boot/issues/2737
McLovin

12

นี่เป็นวิธีแก้ปัญหาเดียวกับที่ @ andy-wilkinson ให้มา แต่ใน Spring Boot 1.0 วิธีการปรับแต่ง (... )มีพารามิเตอร์ConfigurableEmbeddedServletContainer

สิ่งที่ควรค่าแก่การกล่าวถึงอีกประการหนึ่งคือ Tomcat จะบีบอัดเนื้อหาประเภทต่างๆtext/htmlเท่านั้นtext/xmlและtext/plainโดยค่าเริ่มต้น ด้านล่างนี้เป็นตัวอย่างที่รองรับการบีบอัด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);
                        }
                    }
            );
        }
    };
}

ฉันลองเพิ่มสิ่งนี้ลงในการกำหนดค่า Java ของฉันและพบว่าการบีบอัดดูเหมือนจะไม่ทำงานเลย ฉันใช้ Spring Boot กับ Tomcat เป็นคอนเทนเนอร์แบบฝังและสงสัยว่ามีสิ่งอื่นใดเพิ่มเติมที่ฉันต้องตั้งค่านอกเหนือจากการกำหนดค่านี้หรือไม่?
Michael Coxon

2
ลองตรวจสอบโดยระบุAccept-Encoding: gzip,deflateส่วนหัวหากคุณใช้ curl:curl -i -H 'Accept-Encoding: gzip,deflate' http://url.to.your.server
matsev

9

Spring Boot 1.4 ใช้สำหรับ 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

เราจะตรวจสอบการบีบอัดนี้ได้อย่างไร?
Bhargav

@Bhargav ดูส่วนหัวการตอบกลับของการตอบกลับ api ของคุณ ควรมีส่วนหัวContent-Encoding:gzip
Sumit Jha


6

การติดฉลาก GZip ใน Tomcat ไม่ทำงานใน Spring Boot Project ของฉัน ผมใช้CompressingFilterพบที่นี่

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

@ user1127860 tnx ใช้งานได้ แต่จะกำหนดค่าตัวกรองนี้ต่อไปหรือไม่ ฉันใช้สปริงบูตและดูเหมือนจะไม่สามารถเพิ่มพารามิเตอร์ init ตามที่คู่มือกล่าวใน web.xml
Spring

5

ในการเปิดใช้งานการบีบอัด GZIP คุณต้องแก้ไขการกำหนดค่าของอินสแตนซ์ Tomcat แบบฝัง ในการทำเช่นนั้นคุณประกาศEmbeddedServletContainerCustomizerbean ในคอนฟิกูเรชัน Java ของคุณแล้วลงทะเบียนTomcatConnectorCustomizerกับมัน

ตัวอย่างเช่น:

@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);
                }
            });
        }
    };
}

ดูเอกสาร Tomcatสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกการกำหนดค่าการบีบอัดต่างๆที่มีให้

คุณบอกว่าคุณต้องการเปิดใช้งานการบีบอัดแบบเลือก วิธีการข้างต้นอาจเพียงพอทั้งนี้ขึ้นอยู่กับเกณฑ์การคัดเลือกของคุณ ช่วยให้คุณสามารถควบคุมการบีบอัดตาม User-agent ของคำร้องขอขนาดของการตอบกลับและประเภท mime ของการตอบกลับ

หากสิ่งนี้ไม่ตรงกับความต้องการของคุณฉันเชื่อว่าคุณจะต้องทำการบีบอัดในคอนโทรลเลอร์ของคุณและส่งคืนการตอบสนองแบบไบต์ [] ด้วยส่วนหัวการเข้ารหัสเนื้อหา gzip


1
อะไรคือความแตกต่างระหว่างคำตอบของคุณกับตัวเลือกในการตั้งค่าบน application.properties server.compression.enabled = true server.compression.mime-types = application / json, application / xml, text / html, text / xml, text / plain, application / javascript, text / css
lukass77

คำตอบนี้เขียนขึ้นก่อนที่จะมีการกำหนดค่าการบีบอัดตามคุณสมบัติ เทียบเท่ากัน แต่วิธีการตามคุณสมบัตินั้นง่ายกว่าดังนั้นฉันขอแนะนำให้ใช้สิ่งนั้น
Andy Wilkinson

เพียงแค่ต้องการแบ่งปันว่าในกรณีของฉัน tomcat อยู่หลังตัวโหลดบาลานเซอร์ที่รับ https และส่งต่อคำขอไปยัง tomcat เป็น http เมื่อฉันใช้การตอบสนองของโซลูชัน application.properties ไม่ใช่ gzip แต่เมื่อฉันใช้โซลูชันการกำหนดค่าแบบโปรแกรมบนตัวเชื่อมต่อฉันได้รับ การตอบกลับ gzip พร้อมคำขอ https LB
lukass77

คำถามอื่นในกรณีที่ฉันใช้โซลูชัน application.properties .. และกำหนดตัวเชื่อมต่อเพิ่มเติมอีก 2 ตัวบนพอร์ต 8081 และ 8082 .. แอปพลิเคชันการบีบอัดกับคอนเนคเตอร์ทั้งหมดหรือเพียงแค่เชื่อมต่อกับ 8080
lukass77

ฉันยืนยันสิ่งนี้การบังคับใช้กับพอร์ต 8080 เท่านั้นแม้ว่าคุณจะเปิดตัวเชื่อมต่อเพิ่มเติม .. ฉันคิดว่าข้อผิดพลาดควรเปิดในสิ่งนี้เพื่อบูตสปริง ?? .. ดังนั้นวิธีแก้ปัญหาสำหรับฉันเท่านั้นคือการกำหนดค่าทางโปรแกรมสำหรับแต่ละตัวเชื่อมต่อ ไม่ใช่ application.properties
lukass77

0

ฉันมีปัญหาเดียวกันในโครงการ Spring Boot + Spring Data เมื่อเรียกใช้ไฟล์@RepositoryRestResource.

ปัญหาคือประเภท MIME ที่ส่งคืน ซึ่งก็คือapplication/hal+json. การเพิ่มลงในserver.compression.mime-typesคุณสมบัติช่วยแก้ปัญหานี้ให้ฉันได้

หวังว่านี่จะช่วยคนอื่นได้!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.