【问题标题】:Serve Gzipped content with Java Servlets使用 Java Servlet 提供 Gzipped 内容
【发布时间】:2010-12-24 04:33:59
【问题描述】:

我想知道是否有一种 简单 的方式来使用 Java Servlet 提供 GZipped 内容。我已经启动并运行了该应用程序,因此所需的修改应该太繁重了。

我可以在 doPost/doGet 方法的末尾访问响应对象,所以我正在寻找类似的东西

response.setGzip(true);

不必那么简单,但它会是理想的。

非常感谢

【问题讨论】:

    标签: java servlets gzip


    【解决方案1】:

    根据您的容器,容器很可能会为您执行此操作。它可能会自动执行,或者您可能需要手动配置它来为您执行此操作。这种方法的优点是零代码更改。同样,根据容器,您可以根据请求的来源或来源浏览器有条件地启用/禁用压缩。

    对于 Tomcat,请查看 HTTP 配置页面上的压缩属性(v5.5v6.0)。

    【讨论】:

      【解决方案2】:

      基本上有两种方式:

      • 在应用服务器中配置它。例如在 Tomcat 中,您只需将conf/server.xml 中的Connectorcompression 属性设置为on
      • response.getOutputStream() 包装在new GzipOutputStream() 中并改为写入。

      第一种方式会影响整个 webapp,但这真的不应该受到伤害,它几乎是零努力,并且对性能有很大帮助。而且,更重要的是,与第二种方式相反,如果客户端在使用之前支持 Gzip,它实际上会检查请求标头。当您无头地选择第二种方式时,大约 10% 的万维网用户将无法访问您的 Web 应用程序。这真的不是单线任务。

      您可以找到here 的高级示例FileServlet,它支持每个 Gzip 并根据请求标头进行检查。您可能会从中获得新的见解。

      【讨论】:

      • 我看到一些 servlet 过滤器也可以做到这一点?第三种方式?应该首选哪个?
      • @user01:servlet 过滤器采用第二种方式(以通用的可重用方式,无需在所有 servlet 上复制粘贴逻辑)。 OmniFaces 有一个:showcase.omnifaces.org/filters/GzipResponseFilter
      • 感谢您的快速评论!那么第一种应该是为所有网络应用程序资源启用 gzip 的首选方式吗?
      • @user01:如果可能,那通常是首选。但是过滤器从 webapp 端提供了更细粒度的控制/配置。
      【解决方案3】:

      查看 GzipOutputStream 类。像这样的:

      response.setContentType(...)
      GzipOutputStream os = new GzipOutputStream(response.getOutputStream);
      //write to os
      Writer writer = new PrintWriter(os);
      

      然后像平常一样使用 writer。

      【讨论】:

      • 查看 Jonathan Feinberg 的解决方案 :)
      【解决方案4】:

      这是我在学习 servlet 时使用的。也许没有用,但工作! 将下面的代码放入 public class GZIPEncodingServlet extends HttpServlet {...}

      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
          if (req.getHeader("Accept-Encoding").contains("gzip")) {
      
              // 'try' block need for closing of stream, of course we can use 'close()' method for our 'PrintWriter' too
              try (PrintWriter printWriter = new PrintWriter(new GZIPOutputStream(resp.getOutputStream()))) {
      
                  resp.setHeader("Content-Encoding", "gzip"); // Client must understood what we're sending him
                  printWriter.write("Hello world from gzip encoded html"); // What is sending?
              }
      
          } else {
              resp.getWriter().write("Can't encode html to gzip :(");
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        如果您真的、真的不想再摆弄 Java 代码,您还可以考虑在您的 servlet 容器前挂接一个 Apache 服务器。

        如果您有大量静态内容,这实际上可以提高您的性能,因为 Apache 处理静态页面比任何 servlet 容器都要快一些。因此,您可以将其配置为仅将 servlet 请求委托给 localhost 上的 servlet 容器。

        Apache 有方便的内置选项来压缩输出。我不记得如何设置它们,但它既简单又多才多艺。它与浏览器协商它们可以处理什么,等等。如有疑问,Apache 通常会比任何 Java 容器在压缩方法上更加精明和最新。

        【讨论】:

          【解决方案6】:

          如果您在 Tomcat 上,连接器可以为您进行压缩。这是我的配置,

          <Connector port="8000"
           compression="on" 
           compressionMinSize="1024" 
           compressableMimeType="text/html,text/xml" 
           ...
          /> 
          

          如果你在 Tomcat 前面运行 Apache httpd,你应该使用 mod_gzip,它会做得更好。

          【讨论】:

            【解决方案7】:

            只是想让你知道我最后做了什么。

            我做了一个如下所示的请求类包装器:

            public class GzippedResponse extends HttpServletResponseWrapper{
            
              private PrintWriter pw;
            
              private GzippedResponse(HttpServletResponse response){
                super(response);
                try{
                  pw = new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
                }catch(Exception e){
                  throw new ApiInternalException("Failed to create a Gzipped Response", e);
                }
              }
            
              public static GzippedResponse wrap(HttpServletResponse response){
                return new GzippedResponse(response);
              }
            
              @Override
              public PrintWriter getWriter() throws IOException {
                return pw;
              }  
            }
            

            然后在我的BaseAction 上,这基本上是其他“操作”的 TemplateMethod,我将响应包装如下:

            if(supportsCompression(request)){
              response.setHeader("Content-Encoding", "gzip");
              response = GzippedResponse.wrap(response);
            }
            action.macroExecute(request,response);
            

            我认为它足够干净。如果您发现可以改进的地方,请告诉我。谢谢大家的回答!

            【讨论】:

            • 这并没有包含最重要的部分,即输出流。
            猜你喜欢
            • 2010-09-13
            • 1970-01-01
            • 2011-03-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-26
            • 1970-01-01
            • 2011-01-12
            相关资源
            最近更新 更多