Руководство по HTTP-куки в Java

Руководство по HTTP-куки в Java

1. обзор

В этой статье мы собираемся исследовать низкоуровневые операции с сетевым программированием на Java. Мы более подробно рассмотрим файлы cookie.

Платформа Java поставляется со встроенной сетевой поддержкой, включенной в пакетjava.net:

import java.net.*;

2. HTTP-куки

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

Однако cookie-файлы, как мы знаем, позволяют установить сеанс между клиентом и сервером таким образом, чтобы сервер мог запомнить клиента по нескольким парам ответов на запросы.

Отныне из этого раздела мы узнаем, как использовать куки-файлы для улучшения взаимодействия между клиентом и сервером в сетевом программировании Java.

Основной класс в пакетеjava.net для обработки файлов cookie -CookieHandler. Существуют и другие вспомогательные классы и интерфейсы, такие какCookieManager,CookiePolicy,CookieStore иHttpCookie.

3. КлассCookieHandler

Рассмотрим этот сценарий; мы связываемся с сервером вhttp://example.com или с любым другим URL-адресом, который использует протокол HTTP, объект URL-адреса будет использовать механизм, называемый обработчиком протокола HTTP.

Этот обработчик протокола HTTP проверяет, есть ли в системе экземплярCookieHandler по умолчанию. Если есть, он призывает его взять на себя ответственность за государственное управление.

Таким образом, классCookieHandler предназначен для обеспечения механизма обратного вызова в интересах обработчика протокола HTTP.

CookieHandler - абстрактный класс. У него есть статический методgetDefault(), который можно вызвать для получения текущей установкиCookieHandler, или мы можем вызватьsetDefault(CookieHandler), чтобы установить нашу собственную. Обратите внимание, что вызовsetDefault устанавливает объектCookieHandler в масштабе всей системы.

Он также имеетput(uri, responseHeaders) для сохранения любых файлов cookie в хранилище файлов cookie. Эти файлы cookie извлекаются из заголовков ответа HTTP-ответа от заданного URI. Он вызывается каждый раз при получении ответа.

Связанный метод API -get(uri,requestHeaders) извлекает файлы cookie, сохраненные под данным URI, и добавляет их вrequetHeaders. Он вызывается непосредственно перед отправкой запроса.

Все эти методы должны быть реализованы в конкретном классеCookieHandler. На этом этапе нашего внимания заслуживает классCookieManager. Этот класс предлагает полную реализацию классаCookieHandler для наиболее распространенных случаев использования.

В следующих двух разделах мы рассмотрим классCookieManager; сначала в режиме по умолчанию, а затем в пользовательском режиме.

4. По умолчаниюCookieManager

Чтобы иметь полную структуру управления файлами cookie, нам нужны реализацииCookiePolicy иCookieStore.

CookiePolicy устанавливает правила приема и отклонения файлов cookie. Конечно, мы можем изменить эти правила в соответствии с нашими потребностями.

Далее -CookieStore делает именно то, что предполагает его название, у него есть методы для сохранения и получения файлов cookie. Естественно, мы можем настроить механизм хранения здесь, если нам это нужно.

Давайте сначала посмотрим на значения по умолчанию. Чтобы создатьCookieHandler по умолчанию и установить его как общесистемное значение по умолчанию:

CookieManager cm = new CookieManager();
CookieHandler.setDefault(cm);

Следует отметить, что по умолчаниюCookieStore будет иметь энергозависимую память, т.е. он живет только на протяжении всей жизни JVM. Чтобы иметь более постоянное хранилище для файлов cookie, мы должны настроить его.

Когда дело доходит доCookiePolicy, реализация по умолчанию -CookiePolicy.ACCEPT_ORIGINAL_SERVER. Это означает, что если ответ получен через прокси-сервер, то cookie будет отклонен.

5. ПользовательскийCookieManager

Теперь давайте настроимCookieManager по умолчанию, предоставив наш собственный экземплярCookiePolicy илиCookieStore (или обоих).

5.1. CookiePolicyс

CookiePolicy для удобства предоставляет несколько предопределенных реализаций:

  • CookiePolicy.ACCEPT_ORIGINAL_SERVER - могут быть сохранены только куки с исходного сервера (реализация по умолчанию)

  • CookiePolicy.ACCEPT_ALL - все файлы cookie могут быть сохранены независимо от их происхождения

  • CookiePolicy.ACCEPT_NONE - файлы cookie не могут быть сохранены

Чтобы просто изменить текущийCookiePolicy без реализации нашего собственного, мы вызываемsetCookiePolicy в экземпляреCookieManager:

CookieManager cm=new CookieManager();
cm.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

Но мы можем сделать намного больше настроек, чем это. Зная поведениеCookiePolicy.ACCEPT_ORIGINAL_SERVER, предположим, что мы доверяем определенному прокси-серверу и хотим принимать от него файлы cookie поверх исходного сервера.

Нам нужно будет реализовать интерфейсCookiePolicy и реализовать методshouldAccept; здесь мы изменим правило принятия, добавив доменное имя выбранного прокси-сервера.

Назовем новую политику -ProxyAcceptCookiePolicy. Он в основном отклоняет любой другой прокси-сервер из своей реализацииshouldAccept, кроме данного прокси-адреса, а затем вызывает методshouldAccept дляCookiePolicy.ACCEPT_ORIGINAL_SERVER для завершения реализации:

public class ProxyAcceptCookiePolicy implements CookiePolicy {
    private String acceptedProxy;

    public boolean shouldAccept(URI uri, HttpCookie cookie) {
        String host = InetAddress.getByName(uri.getHost())
          .getCanonicalHostName();
        if (HttpCookie.domainMatches(acceptedProxy, host)) {
            return true;
        }

        return CookiePolicy.ACCEPT_ORIGINAL_SERVER
          .shouldAccept(uri, cookie);
    }

    // standard constructors
}

Когда мы создаем экземплярProxyAcceptCookiePolicy, мы передаем строку адреса домена, от которого мы хотели бы принимать файлы cookie в дополнение к исходному серверу.

Затем мы устанавливаем этот экземпляр как политику cookie для экземпляраCookieManager, прежде чем устанавливать его как CookieHandler по умолчанию:

CookieManager cm = new CookieManager();
cm.setCookiePolicy(new ProxyAcceptCookiePolicy("example.com"));
CookieHandler.setDefault(cm);

Таким образом, обработчик файлов cookie будет принимать все файлы cookie с исходного сервера, а также файлы сhttp://www.example.com.

5.2. CookieStoreс

CookieManager добавляет файлы cookie вCookieStore для каждого ответа HTTP и извлекает файлы cookie изCookieStore для каждого запроса HTTP.

Реализация по умолчаниюCookieStore не имеет постоянства, она скорее теряет все свои данные при перезапуске JVM. Больше похоже на оперативную память в компьютере.

Поэтому, если мы хотим, чтобы наша реализацияCookieStore вела себя как жесткий диск и сохраняла файлы cookie при перезапусках JVM, мы должны настроить ее механизм хранения и извлечения.

Следует отметить, что мы не можем передать экземплярCookieStore вCookieManager после создания. Наш единственный вариант - передать его во время созданияCookieManager или получить ссылку на экземпляр по умолчанию, вызвав новыйCookieManager().getCookieStore() и дополнив его поведение.

Вот реализацияPersistentCookieStore:

public class PersistentCookieStore implements CookieStore, Runnable {
    private CookieStore store;

    public PersistentCookieStore() {
        store = new CookieManager().getCookieStore();
        // deserialize cookies into store
        Runtime.getRuntime().addShutdownHook(new Thread(this));
    }

    @Override
    public void run() {
        // serialize cookies to persistent storage
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        store.add(uri, cookie);

    }

    // delegate all implementations to store object like above
}

Обратите внимание, что мы получили ссылку на реализацию по умолчанию в конструкторе.

Мы реализуемrunnable, чтобы мы могли добавить ловушку завершения работы, которая запускается, когда JVM завершает работу. Внутри методаrun мы сохраняем все наши файлы cookie в памяти.

Мы можем сериализовать данные в файл или любое подходящее хранилище. Также обратите внимание, что внутри конструктора мы сначала считываем все файлы cookie из постоянной памяти вCookieStore. Эти две простые функции делаютCookieStore по умолчанию постоянным (упрощенно).

6. Заключение

В этом руководстве мы рассмотрели файлы cookie HTTP и показали, как получить к ним доступ и манипулировать ими программно.

Полный исходный код статьи и все фрагменты кода можно найти вGitHub project.