Изначально я хотел написать механизм проектирования aop, но недавно меня немного перегрузили сессии, поэтому я потратил некоторое время, чтобы разобраться с некоторыми вещами, связанными с сессией.
содержание
- Начиная с безгражданства протокола http
- Cookie
- Принцип механизма cookie
- Определение файлов cookie в servlet-api
- Атрибут файла cookie
- Создать файлы cookie
- Обновление файлов cookie
- Удаление файлов cookie
- получить cookie из запроса
- Гомология файлов cookie и междоменное использование
- Ограничение количества и размера файлов cookie и политика обработки
- Session
Начиная с безгражданства протокола http
HTTP — это протокол без сохранения состояния. Раньше я не совсем понимал это безгражданство, потому что нижний уровень HTTP - это TCP. Поскольку это TCP, это длинное соединение. Этот процесс предназначен для поддержания состояния соединения. Почему вы говорите, что http не имеет состояния? Давайте сначала разберемся с этими двумя понятиями:
без подключения и без гражданства
-
нет соединения
На одно соединение обрабатывается только один запрос, сервер обрабатывает один запрос от клиента и отключается после ответа клиента;
-
нет статуса
Это означает, что сервер рассматривает каждый запрос, отправленный клиентом, как новый запрос, а предыдущая сессия и следующая сессия не связаны;
Измерение без установления соединения — это соединение, а измерение без сохранения состояния — это запрос; http основан на tcp, а постоянное соединение используется по умолчанию, начиная с http1.1; в этом процессе соединения клиент может отправлять несколько запросов на сервер, но каждый из них нет связи между запросами; если подумать об этом таким образом, становится легче понять концепцию безгражданства.
постоянное соединение
持久连接,本质上是客户端与服务器通信的时候,建立一个持久化的TCP连接,这个连接不会随着请求结束而关闭,通常会保持连接一段时间。
Существует два существующих типа постоянных соединений: постоянное соединение для HTTP/1.0+ и постоянное для HTTP/1.1.
- поддержка активности для HTTP/1.0+
Сначала откроем картинку:
Это изображение является информацией заголовка запроса при запросе www.baidu.com. Здесь нам нужно обратить внимание на:connection: keep-alive
Каждый раз, когда мы отправляем HTTP-запрос, он будет сопровождаться соединением: keep-alive, этот параметр должен объявлять постоянное соединение.
- HTTP/1.1 постоянный
Постоянное соединение HTTP/1.1 включено по умолчанию.Только если заголовок содержит connection:close, соединение будет закрыто после завершения транзакции. Конечно, сервер и клиент могут закрыть постоянные соединения в любое время.
Когда отправляется заголовок connection:close, клиент не может отправлять дополнительные запросы по этому соединению. Конечно, в соответствии с характеристиками постоянных соединений должна передаваться правильная длина содержимого.
Кроме того, согласно природе HTTP/1.1, постоянные соединения не должны устанавливаться с клиентами HTTP/1.0. Наконец, будьте готовы к репосту.
http без гражданства
Хорошо, давайте сначала уточним, к чему относится субъект этого состояния? Это должна быть информация, которая поддерживается сервером для взаимодействия с клиентом (также известная как информация о состоянии); Поскольку HTTP сам по себе не сохраняет никакой информации о состоянии пользователя, HTTP является протоколом без сохранения состояния.
Как сохранить информацию о состоянии
Прежде чем говорить об этой проблеме, давайте рассмотрим, почему http не делает этого сам по себе: то есть, чтобы сделать http с отслеживанием состояния.
-
http сам для достижения поддержания состояния
Из приведенного выше понимания безгражданства, если вам сейчас нужно сделать сам http с состоянием, это означает, что протокол http должен сохранять информацию о состоянии взаимодействия; не говоря уже о том, подходит ли этот метод, но с точки зрения поддержания информация о состоянии, стоимость очень высока, потому что, поскольку информация о состоянии сохраняется, некоторые последующие действия также должны зависеть от информации о состоянии.
Исторически сложилось так, что исходный протокол http использовался только для просмотра статических файлов, а протокола без сохранения состояния было достаточно, и бремя реализации было легким. Однако с непрерывным развитием веб-технологий все больше и больше сценариев требуют сохранения информации о состоянии; с одной стороны, сам http не изменит своих характеристик без состояния (по крайней мере, пока), с другой стороны, бизнес-сценарий остро нуждается в для поддержания состояния, то в это время необходимо «украсить» http и внедрить какие-то другие механизмы для достижения состояния.
-
система cookie и сеансов
Информация о состоянии поддерживается за счет внедрения системных механизмов файлов cookie и сеансов. То есть, когда пользователь обращается к серверу в первый раз, в заголовке ответа сервера обычно появляется заголовок ответа Set-Cookie. Здесь файл cookie фактически устанавливается локально. Когда пользователь снова обращается к серверу, http прикрепит этот файл cookie. к прошлому, и файл cookie хранится в файле cookie.Такая информация, как sessionId, передается на сервер, чтобы подтвердить, принадлежит ли он к тому же сеансу.
Cookie
Файл cookie — это небольшой объем информации, отправляемый сервером клиенту (браузеру) в виде {ключ:значение}.
Принцип механизма cookie
Когда клиент запрашивает сервер, если серверу необходимо записать статус пользователя, он использует ответ для выдачи файла cookie браузеру клиента. Браузер клиента сохранит файл cookie. Когда браузер снова запрашивает сервер, браузер отправляет запрошенный URL-адрес вместе с файлом cookie на сервер. Сервер получает статус пользователя, проверяя этот файл cookie.
Давайте узнаем больше о файлах cookie, рассмотрев определение и атрибуты класса Cookie в servlet-api.
Определение файлов cookie в servlet-api
public class Cookie implements Cloneable, Serializable {
private static final long serialVersionUID = -6454587001725327448L;
private static final String TSPECIALS;
private static final String LSTRING_FILE =
"javax.servlet.http.LocalStrings";
private static ResourceBundle lStrings =
ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
private String name;
private String value;
private String comment;
private String domain;
private int maxAge = -1;
private String path;
private boolean secure;
private int version = 0;
private boolean isHttpOnly = false;
//....省略其他方法
}
Атрибут файла cookie
-
name
Имя файла cookie. После создания файла cookie имя нельзя изменить.
-
value
значение файла cookie
-
comment
Описание цели этого файла cookie. Это описание отображается, когда браузер отображает информацию о файлах cookie.
-
domain
Доменное имя, которое может получить доступ к файлу cookie. Если установлено значение «.baidu.com», все домены, оканчивающиеся на «baidu.com», могут получить доступ к файлу cookie; первый символ должен быть «.»
-
maxAge
Срок действия файла cookie в секундах.
- Если это положительное число, оно истечет через maxAge секунд.
- Если число отрицательное, файл cookie является временным файлом cookie, он становится недействительным после закрытия браузера, и браузер не сохраняет файл cookie ни в какой форме.
- Если он равен 0, это означает удаление файла cookie.
-
path
Путь использования этого файла cookie. Например:
- path=/, указывающий, что contextPath под этим доменным именем может получить доступ к куки.
- path=/app/, доступ к куки могут получить только программы, чей contextPath равен «/app».
Когда путь задан, он заканчивается на «/».
-
secure
Передается ли файл cookie только с использованием безопасного протокола. Протоколы безопасности здесь включают HTTPS, SSL и т. д. По умолчанию ложно.
-
version
Номер версии, используемый этим файлом cookie.
- 0 означает следовать спецификации файлов cookie Netscape, которая в настоящее время используется большинством из них;
- 1 означает следование спецификации W3C RFC2109, спецификация слишком строгая и трудная для реализации.
По умолчанию 0 в спецификации сервлета;
-
isHttpOnly
Атрибут HttpOnly используется для ограничения программного интерфейса, отличного от протокола HTTP, для доступа к клиентскому файлу cookie; то есть, если вы хотите получить файл cookie httponly на стороне клиента, единственный способ — использовать AJAX, поставить операцию получение файла cookie на сервере, получение После запроса ajax, отправленного клиентом, результат будет возвращен клиенту через HTTP. Это может эффективно предотвратить атаки XSS.
Вышеупомянутые атрибуты, за исключением атрибутов имени и значения, будут отправлены, другие атрибуты не читаются клиентом и не могут быть отправлены.
Создать файлы cookie
Cookie cookie = new Cookie("cookieSessionId","qwertyuiop");
cookie.setDomain(".baidu.com"); // 设置域名
cookie.setPath("/"); // 设置路径
cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期为永久
response.addCookie(cookie); // 回写到客户端
Создание файла cookie может быть выполнено только описанным выше способом, поскольку в классе Cookie предоставляется только такой конструктор.
//Cookie的构造函数
public Cookie(String name, String value) {
if (name != null && name.length() != 0) {
//判断下是不是token
//判断是不是和Cookie的属性字段重复
if (this.isToken(name) && !name.equalsIgnoreCase("Comment") &&
!name.equalsIgnoreCase("Discard") &&
!name.equalsIgnoreCase("Domain") &&
!name.equalsIgnoreCase("Expires") &&
!name.equalsIgnoreCase("Max-Age") &&
!name.equalsIgnoreCase("Path") &&
!name.equalsIgnoreCase("Secure") &&
!name.equalsIgnoreCase("Version") && !name.startsWith("$")) {
this.name = name;
this.value = value;
} else {
String errMsg =
lStrings.getString("err.cookie_name_is_token");
Object[] errArgs = new Object[]{name};
errMsg = MessageFormat.format(errMsg, errArgs);
throw new IllegalArgumentException(errMsg);
}
} else {
throw new IllegalArgumentException(lStrings.getString
("err.cookie_name_blank"));
}
}
Обновление файлов cookie
Из исходного кода может быть известно, что сам файл cookie не предоставляет метод модификации; в практических приложениях исходный файл cookie обычно перезаписывается с использованием файла cookie с тем же именем для достижения цели обновления.
Но предпосылка этой модификации заключается в том, что требуется заголовок сообщения Set-Cookie с тем же доменом и путем.
Cookie cookie = new Cookie("cookieSessionId","new-qwertyuiop");
response.addCookie(cookie);
Удаление файлов cookie
Как и обновление файла cookie, сам файл cookie не предоставляет метода для его удаления, но из предыдущего анализа атрибута файла cookie мы узнали, что файл cookie можно удалить, установив для параметра maxAge значение 0.
Cookie cookie = new Cookie("cookieSessionId","new-qwertyuiop");
cookie.setMaxAge(0);
response.addCookie(cookie);
Вышеупомянутое удаление находится под нашим контролем, но есть также некоторые операции удаления, которые мы не можем контролировать или бессознательно:
- Если значение maxAge отрицательное, файл cookie удаляется при закрытии браузера.
- Постоянные файлы cookie удаляются по истечении срока их действия.
- Когда количество файлов cookie в браузере достигает предела, файл cookie будет удален, чтобы освободить место для вновь созданного файла cookie.
На самом деле, во многих случаях мы ориентируемся на последнее. Верхний предел будет рассмотрен позже.
получить cookie из запроса
Cookie[] cookies = request.getCookies();
Гомология файлов cookie и междоменное использование
Мы знаем политику браузера о том же происхождении:
URL-адрес состоит из протокола, доменного имени, порта и пути. Если протокол, доменное имя и порт двух URL-адресов совпадают, они имеют одно и то же происхождение. Политика браузера в отношении одного и того же источника запрещает «документам» или сценариям из разных источников читать или устанавливать определенные свойства для текущего «документа».
Для файлов cookie тот же источник файлов cookie обращает внимание только на доменное имя, игнорируя протокол и порт. Таким образом, файлы cookie https://localhost:80/ и http://localhost:8080/ являются общими.
Файлы cookie не являются междоменными, доменное имя второго уровня отличается без какой-либо обработки. (wenku.baidu.com и baike.baidu.com).
Ограничение количества и размера файлов cookie и политика обработки
IE6.0 | IE7.0/8.0 | Opera | FF | Safari | Chrome | |
---|---|---|---|---|---|---|
количество/шт. | 20/домен | 50/домен | 30/домен | 50/домен | неограниченный | 53/домен |
размер/байт | 4095 | 4095 | 4096 | 4097 | 4097 | 4097 |
注:数据来自网络,仅供参考
Поскольку браузер имеет ограничение на количество файлов cookie, если количество файлов cookie превышено, будут применяться некоторые стратегии отбраковки. в этой статьеBrowser cookie restrictionsУпомянутые стратегии выбраковки следующие:
The least recently used (LRU) approach automatically kicks out the oldest cookie when the cookie limit has been reached in order to allow the newest cookie some space. Internet Explorer and Opera use this approach.
Метод наименее использовавшихся (LRU): автоматически отбраковывать самые старые файлы cookie при достижении предела файлов cookie, чтобы освободить место для самых новых файлов cookie. Internet Explorer и Opera используют этот метод.
Firefox делает что-то странное: кажется, что он случайным образом решает, какие файлы cookie оставить, хотя последний набор файлов cookie всегда сохраняется. Кажется, он вообще не следует какой-либо схеме. Вывод: не превышайте лимит файлов cookie в Firefox. .
Firefox решает удалить файл cookie в наборе файлов cookie случайным образом, и эмпирического правила не существует. Поэтому лучше не превышать лимит файлов cookie в Firefox.
Если размер превышает длину, он будет перехвачен и отброшен напрямую;
Session
Механизм Cookie компенсирует отсутствие безгражданства протокола HTTP. До появления Session практически все веб-сайты использовали файлы cookie для отслеживания сеансов.
В отличие от файлов cookie, сеансы хранятся на стороне сервера.
Принцип сеансового механизма
Когда клиент запрашивает создание сеанса, сервер сначала проверяет, содержит ли уже запрос клиента идентификатор сеанса — sessionId,
- Если этот идентификатор сеанса включен, это означает, что сеанс был создан для этого клиента ранее, и сервер извлекает сеанс для использования в соответствии с идентификатором сеанса (если он не может быть получен, он может создать новый)
- Если запрос клиента не содержит идентификатора сеанса, создайте сеанс для этого клиента и сгенерируйте идентификатор сеанса, связанный с этим сеансом.
Значение sessionId, как правило, представляет собой строку, которую нельзя повторять и которую легко имитировать. Этот идентификатор sessionId будет возвращен клиенту в этом ответе для хранения. Способ сохранения sessionId — это в основном cookie.
HttpSession
HttpSession, как и Cookie, находится в javax.servlet.http; Cookie — это класс, описывающий многие внутренние детали Cookie. HttpSession — это интерфейс, предоставляющий некоторые поведенческие ограничения для реализации сеанса.
public interface HttpSession {
/**
* 返回session的创建时间
*/
public long getCreationTime();
/**
* 返回一个sessionId,唯一标识
*/
public String getId();
/**
*返回客户端最后一次发送与该 session 会话相关的请求的时间
*自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。
*/
public long getLastAccessedTime();
/**
* 返回当前session所在的ServletContext
*/
public ServletContext getServletContext();
public void setMaxInactiveInterval(int interval);
/**
* 返回 Servlet 容器在客户端访问时保持 session
* 会话打开的最大时间间隔
*/
public int getMaxInactiveInterval();
public HttpSessionContext getSessionContext();
/**
* 返回在该 session会话中具有指定名称的对象,
* 如果没有指定名称的对象,则返回 null。
*/
public Object getAttribute(String name);
public Object getValue(String name);
/**
* 返回 String 对象的枚举,String 对象包含所有绑定到该 session
* 会话的对象的名称。
*/
public Enumeration<String> getAttributeNames();
public String[] getValueNames();
public void setAttribute(String name, Object value);
public void putValue(String name, Object value);
public void removeAttribute(String name);
public void removeValue(String name);
/**
* 指示该 session 会话无效,并解除绑定到它上面的任何对象。
*/
public void invalidate();
/**
* 如果客户端不知道该 session 会话,或者如果客户选择不参入该
* session 会话,则该方法返回 true。
*/
public boolean isNew();
}
создать сеанс
Способ создания сеанса — создать его через запрос;
// 1、创建Session对象
HttpSession session = request.getSession();
// 2、创建Session对象
HttpSession session = request.getSession(true);
Эти два одинаковые, если сессия не существует, создайте новую, если она ложна, верните ноль, если идентификатор не существует;
жизненный цикл
Жизненный цикл сеанса относится к процессу от создания объекта сеанса до уничтожения контейнера сервлета. Контейнер сервлета уничтожит объект сеанса по истечении времени сеанса в соответствии со временем выживания, установленным объектом сеанса. После создания сеанса, пока пользователь продолжает доступ, сервер будет обновлять время последнего доступа сеанса и поддерживать сеанс.
В предыдущем однопроцессном приложении сеанс обычно хранился в памяти, и я бы не стал выполнять постоянные операции или использовать сторонние службы для хранения информации о сеансе, такие как Redis. Но в распределенных сценариях такой способ хранения в локальной памяти явно неприменим, т.к. сеансы не могут быть разделены. Скажи это позже.
срок действия сессии
Сеансы обычно хранятся в памяти, а само пространство памяти имеет определенные ограничения, поэтому сеансы должны использовать механизм удаления с истекшим сроком действия, чтобы гарантировать, что информация о сеансе не накапливается все время, чтобы предотвратить переполнение памяти.
Время ожидания сеанса можно установить с помощью свойства maxInactiveInterval.
Если мы хотим сделать сеанс недействительным, это также можно сделать, вызвав метод invalidate() сеанса.
Распределенный сеанс
Прежде всего, почему появляется такое понятие?
Рассмотрим сначала такую задачу, сейчас мое приложение нужно развернуть на 3 машины. Бывает ли такая ситуация, при первом входе запрос идет на машину 1, а потом создается сессия на машине 1, но при втором заходе запрос направляется на машину 2, но уже на машину 2 У меня нет информации о моем сеансе, поэтому мне нужно снова войти в систему. Конечно, это можно решить с помощью стратегии загрузки IP HASH в nginx. Для одного и того же IP запрос пойдет на одну и ту же машину.
Но бизнес становится все больше и больше, дробится все больше и больше, а количество машин увеличивается; очевидно, такого решения недостаточно. В настоящее время вам необходимо подумать о том, следует ли размещать информацию о сеансе на отдельной машине, поэтому проблема, которую необходимо решить с помощью распределенных сеансов, на самом деле является проблемой совместного использования сеансов в распределенной среде.
Как показано на рисунке выше, существует множество способов независимого развертывания сеансов, которые могут быть независимой службой базы данных или службой кэширования (в настоящее время широко используемый метод Redis заключается в использовании Redis в качестве сервера кэширования сеансов).
Ссылаться на
- https://www.cnblogs.com/icelin/p/3974935.html
- https://www.nczonline.net/blog/2008/05/17/browser-cookie-restrictions/
- https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE