HTTP-сессия в мире Java
В любом веб-приложении одним из краеугольных вопросов является поддержка клиентских сессий. Платформа JavaEE не исключение и для этих целей в ней существует специализированный HttpSession API, доступ к которому есть у любого веб-приложения, развёрнутого в некотором сервлет-контейнере. Что же из себя представляют эти самые сессии?
Возможно, вам известно, что протокол HTTP и веб-серверы по природе своей являются stateless, и каждый новый запрос от клиента расценивается сервером как абсолютно новый, ничего не знающий об истории предшествующих обращений. Вы скажете, а как же тогда реализуются интернет-магазины, знающие о списке добавленных в корзину товаров своих покупателей?
А что такое сессия?
Сессия — это диалоговое состояние между клиентом и сервером, включающее информацию о предыдущих запросах клиента и ответах сервера. В силу того, что протокол и сами веб-сервера не обеспечивают сохранение состояния, то единственной возможностью для этого является передача всей необходимой информации о запросе в нём самом.
Чтобы этого не делать, каждый запрос от данного клиента сервер ассоциирует с некоторой уникальной информацией об установленной сессии (идентификатор сессии), пробрасывая её в каждом запросе и ответе. Для передачи данного UID наиболее популярными являются такие способы, как использование пользовательских cookies, скрытые поля формы и передача непосредственно в адресе запроса.
При разработке веб-приложения, конечно, функцию генерации UID и последующей его передачи от клиента к серверу может взять на себя само приложение. Но тогда разработчик будет ответственен за все возможные обращения, каждый раз проверяя, а не забыл ли он передать это значение, при этом генерируя огромное количество boilerplate-кода.
Что же в Java Enterprise?
К великому счастью, разработчики JavaEE освобождены от такой рутины и выполнение данной задачи взвалено на плечи контейнера, в пределах которого развёрнуто приложение. Осталось понять, каким же образом он это делает?
Работа с пользовательскими сессиями веб-приложений в JavaEE вынесена в раздел Servlet API и осуществляется средствами интерфейса javax.servlet.http.HttpSession, который предоставляет высокоуровневые методы работы с ними. Непосредственная реализация уже располагается в библиотеке servlet-api.jar используемого контейнера сервлетов и напрямую зависит от него. Существует два способа получения ссылки на объект пользовательского сеанса из объекта клиентского запроса javax.servlet.http.HttpServletRequest, используя методы Servlet API:
- HttpSession request.getSession(boolean create) — для ложного значения параметра create данный метод возвращает объект сессии, если он был создан у данного запроса, и null в противном случае; в случае истинного значения create данный метод равносилен методу п.2.
- HttpSession request.getSession() — если сеанс не установлен, то контейнер его создаёт, иначе возвращает уже созданный объект сессии.
В момент, когда сеанс установлен, сервлет-контейнер создаёт пользовательский cookie с именем JSESSIONID, значение которого содержит уникальный идентификатор сессии (это же значение можно получить методом String getId() объекта HttpSession). Наряду с этим, в рамках контейнера определяется дефолтное значение таймаута сессии — время неактивного состояния пользователя, приводящее к устареванию его сеанса связи с сервером.
Данное значение конфигурируется на уровне контейнера сервлетов либо непосредственно в веб-приложении на уровне дескриптора развёртывания web.xml или непосредственным вызовом метода void setMaxInactiveInterval(int interval) у объекта сессии. Начиная с версии Servlet API 3.0, также можно задать и время жизни куки JSESSIONID в конфиге web.xml, уничтожение которой также приведёт к запросу на повторное установление сеанса между клиентом и сервером. Кусок дескриптора развертывания web.xml:
<session-config> <!-- Timeout of inactivity in minutes --> <session-timeout>15</session-timeout> <cookie-config> <http-only>true</http-only> <path>/</path> <!-- Cookie lifetime in seconds --> <max-age>900</max-age> </cookie-config> </session-config>
А что же будет, если пользовательские «печеньки» запрещены на клиентской машине? Данный факт будет выявлен сервером автоматически и для поддержания сеанса будет использован механизм URL Rewriting, который позволяет передавать UID-сессии непосредственно в адресной строке, например так:
http://www.mysite.com/MyApp/myservlet;jsessionid=1E6FEC0D14D044541DD84D2D013D29ED
А зачем они вообще нужны эти http-сессии и какие в принципе возможности они предоставляют — это уже отдельная тема.
Есть вопрос? Напишите в комментариях!