Перейти к основному содержимому

Руководство по файлам cookie HTTP в Java

· 6 мин. чтения

1. Обзор

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

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

import java.net.*;

2. HTTP-куки

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

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

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

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

3. Класс CookieHandler

Рассмотрим этот сценарий; мы общаемся с сервером по адресу http://foreach.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 ; сначала в режиме по умолчанию, а затем в пользовательском режиме.

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

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

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

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

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

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

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

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

5.1. CookiePolicy

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

  • CookiePolicy.ACCEPT_ORIGINAL_SERVER — могут быть сохранены только файлы cookie с исходного сервера (реализация по умолчанию)
  • 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("foreach.com"));
CookieHandler.setDefault(cm);

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

5.2. CookieStore

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

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

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

Следует отметить, что мы не можем передать экземпляр CookieStore в CookieManager после создания. Наш единственный вариант — передать его во время создания CookieManager или получить ссылку на экземпляр по умолчанию, вызвав new 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 .