Как вернуть кэшированные архивированные HTML-страницы в запрос http-сервлета?

#java #servlets #zip #httpresponse #caching

#java #сервлеты #zip #httpresponse #кэширование

Вопрос:

У меня есть небольшой сервлет, возвращающий несколько HTML-страниц. Содержимое одной из этих страниц довольно сложное, но меняется только каждый час или около того. Однако пользователи часто запрашивают его. Я хочу избежать повторного вычисления его при каждом запросе.

Мне было интересно, можно ли подготовить версию в формате gzip в памяти (массив байтов) и установить ее в качестве ответа на все HTML-запросы для этой страницы. Я бы также пересчитывал новую кэшированную версию gzip-ed каждый час.

Если это возможно, как я могу это сделать? Должен ли я использовать фильтр? Ради этого вопроса мы можем предположить, что все браузеры могут обрабатывать ответы в формате gzip. Я ищу пример кода.

Ответ №1:

После некоторого поиска в Google это, похоже, решение:

 public class MyFilter implements Filter {

    private byte[] my_gzipped_page = ....

    public void doFilter(ServletRequest req, ServletResponse res,
        FilterChain chain) throws IOException, ServletException {

        if (req instanceof HttpServletRequest) {

            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            String ae = request.getHeader("accept-encoding");

            if (ae != null amp;amp; ae.indexOf("gzip") != -1) {

                response.addHeader("Content-Length",
                    Integer.toString(my_gzipped_page.length)); 
                response.addHeader("Content-Encoding", "gzip");

                OutputStream output = response.getOutputStream();
                output.write(my_gzipped_page);
                output.flush();
                output.close();

                return;

            } else ...

        }
    }
    ...
}
  

Ответ №2:

Зачем делать это сложным способом?

Откройте Tomcat /conf/server.xml , найдите <Connector> свой HTTP-порт и отредактируйте его следующим образом, чтобы добавить новый атрибут:

 <Connector ... compression="on">
  

Затем Tomcat автоматически архивирует все ответы, совпадающие compressableMimeType автоматически, когда клиент поддерживает его. Все остальные уважающие себя веб-серверы имеют аналогичную настройку конфигурации.

Комментарии:

1. Но будет ли tomcat повторно архивировать каждый ответ каждый раз? (Я все еще нахожусь в процессе обучения)

2. Да, это произойдет, но на самом деле об этом не стоит беспокоиться. GZIP особенно быстр и дешев. Ваш веб-сервер не выполняет какие-либо другие задания с интенсивной обработкой процессора? Вам лучше установить правильные заголовки кэширования ответов (expires, last-modified и etag) с фильтром, чтобы браузер просто сохранял страницу в кэше в течение определенного времени.

3. Я полностью согласен с правильным заголовком кэширования. На самом деле, я готов пройти дополнительные мили, чтобы создать сверхбыстрый сервлет для относительно статических страниц. Я планирую использовать оба. Большое спасибо за ваш отзыв.

Ответ №3:

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

Для кэширования вы можете сохранить обработанную версию страницы либо на диске, либо в памяти, используя, например, memcache.

Если вы знаете, что вам нужно будет обновлять страницу, скажем, каждый час, вы можете запустить скрипт, например, с помощью crontab, для создания страницы каждый час и просто обслуживать сгенерированную страницу. Это должно быть довольно просто, поскольку вам действительно не нужно учитывать особые соображения в отношении кэширования на стороне сервера.

С другой стороны, если вам нужно проверить, устарела ли страница, прежде чем принимать решение, использовать ли кэшированную версию или новую, это становится немного сложнее. Например, возможно, что проверка устаревших данных почти так же затратна, как и создание страницы.

Не могу дать более конкретный ответ без дополнительной информации.

Комментарии:

1. Предполагая, что у меня есть архивированная версия страницы в байтовом массиве, как мне поместить ее в http-ответ? Я не хочу каждый раз сжимать страницу. Я имею дело с Tomcat, а не с веб-сервером.

2. Ну, Tomcat — это веб-сервер.. Я сам с этим не знаком, но предполагая, что он использует стандартные Java-сервлеты, вы должны иметь возможность устанавливать необходимые заголовки с помощью HttpServletResponse.AddHeader(), а затем отправлять массив байтов с помощью HttpServletResponse.getWriter().print() .