Служите сжатому контенту с сервлетами Java - PullRequest
9 голосов
/ 08 декабря 2009

Мне было интересно, существует ли простой способ обслуживания контента GZipped с помощью Java-сервлетов. У меня уже есть приложение и оно запущено, поэтому необходимые модификации должны быть слишком тяжелыми.

У меня есть доступ к объекту ответа только в конце метода doPost / doGet, поэтому я ищу что-то вроде

response.setGzip(true);

Это не должно быть так просто , но это было бы идеально.

Большое спасибо

Ответы [ 8 ]

10 голосов
/ 08 декабря 2009

Эта статья содержит полный (и краткий) исходный код для ServletFilter, который автоматически сжимается на лету.

4 голосов
/ 08 декабря 2009

В зависимости от вашего контейнера, контейнер, скорее всего, сделает это за вас. Он может делать это автоматически, или вам может потребоваться вручную настроить его, чтобы сделать это для вас. Преимущество этого метода - нулевые изменения кода. И, опять же, в зависимости от контейнера вы можете условно включить / отключить сжатие в зависимости от того, откуда поступил запрос или от исходного браузера.

Для Tomcat посмотрите атрибут сжатия на страницах конфигурации HTTP ( v5.5 , v6.0 ).

3 голосов
/ 08 декабря 2009

Есть в основном 2 способа:

  • Настройте его в appserver. Например, в Tomcat вам просто нужно установить атрибут compression для Connector в conf/server.xml на on.
  • Оберните response.getOutputStream() в new GzipOutputStream() и напишите вместо него.

Первый способ влияет на все веб-приложение, но это действительно не должно повредить, это почти нулевое усилие и большая польза для производительности. И, что более важно, в отличие от второго способа, он фактически проверяет заголовки запросов, если клиент поддерживает Gzip перед его использованием. Когда вы идете по второму пути без головы, тогда около 10% пользователей всемирной сети не смогут получить доступ к вашему веб-приложению. Это действительно не единственная задача.

Вы можете найти здесь расширенный пример FileServlet, который поддерживает каждый Gzip и проверяет это на основе заголовков запроса. Вы можете получить новые идеи из этого.

3 голосов
/ 08 декабря 2009

Посмотрите на класс GzipOutputStream. Примерно так:

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

Тогда используйте писателя, как обычно.

1 голос
/ 08 декабря 2009

Просто хотел, чтобы вы знали, что я закончил делать.

Я сделал оболочку класса запроса, которая выглядит следующим образом:

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

Я думаю, это достаточно чисто. Если вы найдете что-то, что можно улучшить, пожалуйста, дайте мне знать. Спасибо всем за ответы!

1 голос
/ 08 декабря 2009

Если вы находитесь на Tomcat, разъем может выполнять сжатие для вас. Это моя конфигурация,

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

Если вы запускаете Apache httpd перед Tomcat, вы должны использовать mod_gzip, который делает работу намного лучше.

1 голос
/ 08 декабря 2009

Если вы действительно, действительно не хотите больше манипулировать кодом Java, вы можете также подключить сервер Apache перед контейнером сервлета.

Если у вас много статического контента, это может на самом деле повысить производительность для вас, поскольку Apache будет немного быстрее для статических страниц, чем любой контейнер сервлета. Поэтому вы должны настроить его так, чтобы он передавал только запросы сервлетов вашему сервлет-контейнеру на localhost.

Apache имеет удобные встроенные опции для сжатия вывода. Я не помню, как их установить, но это легко и универсально. Он договаривается с браузерами о том, что они могут обработать, и так далее. В случае сомнений Apache, как правило, будет более опытным и современным по методам сжатия, чем любой контейнер Java.

0 голосов
/ 20 мая 2019

Это то, что я использовал при изучении сервлетов. Может быть, не полезно, но работает !!! Приведенный ниже код в открытый класс 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 :(");
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...