I originally wanted to write an AOP design mechanism, but recently I got frustrated by the session thing, so I took a moment to sort out a few things about sessions.

directory

  • Start with the statelessness of the HTTP protocol
    • No connection and stateless
    • A persistent connection
    • HTTP stateless
    • How do I maintain status information
  • Cookie
    • Cookie mechanism
    • Cookie definition in servlet-API
    • Cookie attribute
    • Create a Cookie
    • Cookies are updated
    • Cookies are deleted
    • Gets the Cookie from the request
    • Cookie homology and cross-domain
    • Cookie quantity & size limits and processing policies
  • Session
    • Session Mechanism
    • HttpSession
    • Create a session
    • The life cycle
    • Session validity period
    • Distributed session

Start with the statelessness of the HTTP protocol

HTTP is a stateless protocol. I didn’t understand this before, because HTTP is TCP, and if it’s TCP, it’s a long connection, and this process keeps the connection state, so why is HTTP stateless? Let’s get these two concepts straight:

No connection and stateless

  • There is no connection

    Each connection processes only one request. The server processes one request from the client and disconnects when the client responds.

  • stateless

    Each request sent by the client is considered as a new request by the server, and there is no connection between the last session and the next session.

The connectionless dimension is the connection and the stateless dimension is the request. HTTP is based on TCP, and persistent connections are used by default starting with HTTP1.1; In this connection process, the client can send multiple requests to the server, but there is no connection between the requests. In this way, the concept of statelessness is easy to understand.

A persistent connection

A persistent connection is essentially when a client communicates with a server, establishing a persistent TCP connection that does not close with the end of the request and usually remains open for a period of time.

There are two types of persistent connection: KEEP-alive for HTTP/1.0+ and Persistent for HTTP/1.1.

  • HTTP / 1.0 + keep alive

Let’s start with a picture:

connection: keep-alive
Copy the code

Each time we send an HTTP request, we send a connection:keep-alive, which declares a persistent connection.

  • Persistent HTTP / 1.1

HTTP/1.1 persistent connections are enabled by default. The connection will only be closed after the transaction ends if the header contains connection: close. Of course, the server and client can still close persistent connections at any time.

After sending the Connection: Close header the client cannot send any more requests on that connection. Of course, due to the nature of persistent connections, it is important to transmit the correct Content-Length.

Also, by the nature of HTTP/1.1, persistent connections to HTTP/1.0 clients should not be established. Finally, be sure to be prepared for retransmissions.

HTTP stateless

OK, first of all, what is the subject of this state? It should be information, which is the information maintained by the server to interact with the client (also known as state information); HTTP is a stateless protocol because it does not store any user state information.

How do I maintain status information

Before we get into that, let’s consider why HTTP doesn’t do it itself: that is, make HTTP stateful.

  • HTTP itself implements state maintenance

    If you want to make HTTP stateful by itself, it means that the HTTP protocol needs to store the state of the interaction. Whether this approach is appropriate or not is costly in terms of maintaining state information, since it must also affect subsequent behavior.

    Historically, the original HTTP protocol was used only to browse static files. Stateless protocols were sufficient and the implementation burden was light. However, with the continuous development of Web technology, more and more scenarios need state information to be saved. HTTP itself is not going to change its stateless nature (at least for now), and business scenarios desperately need to stay state. This is the time to “spruce up” HTTP and introduce some other mechanism for stateful implementation.

  • Cookie and session systems

    Cookie and session mechanisms are introduced to maintain state information. When the user accesses the server for the first time, the server responds with a set-cookie header. In this case, a Cookie is Set locally. When the user accesses the server again, HTTP will send the Cookie. There’s a sessionId in the cookie and it goes to the server to make sure it’s the same session.

Cookie

Cookie is a small amount of information sent by the server to the client (browser) in the form of {key: value}.

Cookie mechanism

When a client requests the server, if the server needs to record the user state, it issues a Cookie to the client browser using response. The client browser saves the Cookie. When the browser requests the server again, the browser submits the requested URL along with the Cookie to the server. The server checks the Cookie to get the user’s state.

Let’s take a closer look at cookies by looking at the definition and properties of the Cookie class in servlet-API.

Cookie definition in 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;
    / /... Omit other methods
}
Copy the code

Cookie attribute

  • name

    The name of the cookie, which cannot be changed once the cookie is created

  • value

    The cookie value

  • comment

    Description of the Cookie’s usefulness. This description is displayed when the browser displays Cookie information

  • domain

    The domain name of the Cookie can be accessed. If the Cookie is set to.baidu.com, all domain names ending in baidu.com can access the Cookie. The first character must be “.

  • maxAge

    Cookie validity time, in seconds.

    • If the value is positive, the value expires after maxAge seconds.
    • If the value is negative, the Cookie is a temporary Cookie. The Cookie will become invalid when the browser is closed and the browser will not save the Cookie in any form.
    • If the value is 0, the Cookie is deleted.
  • path

    The usage path of the Cookie. Such as:

    • Path =/, indicating that the Cookie can be accessed by contextPath in the domain name.
    • Path =/app/, only the programs with contextPath set to /app can access the Cookie

    When path is set, it ends with a slash.

  • secure

    Whether the Cookie is transmitted only using a secure protocol. The security protocols include HTTPS and SSL. The default is false.

  • version

    The version number used by the Cookie.

    • 0 means following Netscape’s Cookie specification, which is mostly used today;
    • 1 indicates compliance with THE RFC2109 specification of W3C. The regulations are too strict and difficult to enforce.

    The default in the servlet specification is 0;

  • isHttpOnly

    The HttpOnly attribute is used to restrict access to client cookies by non-HTTP programming interfaces. In other words, if you want to get the httpOnly Cookie on the client side, the only way is to use AJAX, put the Cookie operation on the server side, after receiving the AJAX request sent by the client, the value will be returned to the client through HTTP. This can effectively prevent XSS attacks.

These attributes, except the name and value attributes will be committed, the other attributes are not readable to the client and cannot be committed.

Create a Cookie

Cookie cookie = new Cookie("cookieSessionId"."qwertyuiop");
cookie.setDomain(".baidu.com");             // Set the domain name
cookie.setPath("/");                        // Set the path
cookie.setMaxAge(Integer.MAX_VALUE);        // Set the validity period to permanent
response.addCookie(cookie);                 // Write back to client
Copy the code

Creating cookies can only be done this way, because only such a constructor is provided in the Cookie class.

// The Cookie constructor
public Cookie(String name, String value) {
    if(name ! =null&& name.length() ! =0) {
        // Check whether it is a token
        // Check whether it is the same as the Cookie property field
        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 newIllegalArgumentException(errMsg); }}else {
        throw new IllegalArgumentException(lStrings.getString
        ("err.cookie_name_blank")); }}Copy the code

Cookies are updated

As you can see in the source code, the Cookie itself does not provide methods to modify; In practical applications, cookies with the same name are generally used to overwrite the original Cookie to achieve the purpose of updating.

However, this change requires a set-cookie header with the same domain and path

Cookie cookie = new Cookie("cookieSessionId"."new-qwertyuiop");
response.addCookie(cookie);
Copy the code

Cookies are deleted

Like Cookie updates, cookies themselves do not provide a way to delete; However, as you know from analyzing Cookie properties above, cookies can be deleted by setting maxAge to 0.

Cookie cookie = new Cookie("cookieSessionId"."new-qwertyuiop");
cookie.setMaxAge(0);
response.addCookie(cookie);
Copy the code

The deletion above is under our control; But there are also some deletions that are out of our control or unconscious:

  • If maxAge is negative, the cookie is deleted when the browser closes
  • Persistent cookies are deleted when the expiration date is reached
  • When the number of cookies in the browser reaches the upper limit, the cookies are deleted to create space for new cookies.

In many cases, we focus on the latter. We’ll talk about quantity caps later.

Gets the Cookie from the request

 Cookie[] cookies = request.getCookies();
Copy the code

Cookie homology and cross-domain

We know the browser’s same-origin policy:

A URL consists of a protocol, domain name, port, and path. If the protocol, domain name, and port of two urls are the same, they are of the same origin. The browser’s same-origin policy restricts “document” or scripts from different sources from reading or setting certain properties on the current “document”.

In the case of cookies, the same origin of cookies only focuses on domain names, ignoring protocols and ports. So in general, the cookies of https://localhost:80/ and http://localhost:8080/ are shared.

Cookies are not cross-domain; In the absence of any processing, the secondary domain name is not the same. (wenku.baidu.com and baike.baidu.com).

Cookie quantity & size limits and processing policies

IE6.0 IE7.0/8.0 Opera FF Safari Chrome
The number of/a 20 / domain 50 / domain 30 / domain 50 / domain unlimited 53 / domain
Size/Byte 4095 4095 4096 4097 4097 4097

Note: Data from the network, for reference only

Because browsers have a limit on the number of cookies they can have, they naturally have some sort of elimination strategy if they exceed it. In this article, Browser Cookie Restrictions mention the following culling policies:

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.

Least-recently used (LRU) method: Automatically weed out the oldest cookies when the cookie limit is reached to make room for more recent cookies. Internet Explorer and Opera use this approach.

Firefox does something strange: It seems to get better results than crystals which cookies to keep although the last cookie set is always kept. There doesn’t seem to be Any scheme it’s following at all. Don’t go above the cookie limit in Firefox.

Firefox decides to delete a Cookie from the Cookie set at random without any rules. So it’s best not to exceed the Cookie limit in Firefox.

Anything beyond the size and length is simply intercepted and discarded;

Session

Cookie makes up for the stateless HTTP protocol. Before sessions, almost all websites used cookies to track sessions.

Unlike cookies, sessions store state on the server.

Session Mechanism

When a client requests to create a session, the server first checks whether the request contains a session id – sessionId.

  • If the session ID is already included, a session has already been created for the client. The server retrieves the session using the session ID (if not, a new session may be created).
  • If the client request does not contain a sessionId, a session is created for the client and a sessionId associated with the session is generated

The value of the sessionId is usually a string that is neither duplicated nor easily counterfeited. The sessionId will be returned to the client for storage in this response. The way to save the sessionId is mostly using cookies.

HttpSession

HttpSession, like cookies, is underneath javax.servlet. HTTP; Cookie is a class that describes many of the internal details of a Cookie. HttpSession is an interface that imposes behavioral constraints on session implementation.

public interface HttpSession {
    /** * returns the session creation time */
    public long getCreationTime(a);
    
    /** * returns a sessionId that uniquely identifies */
    public String getId(a);
    
    /** * Returns the time when the client last sent a request related to this session session * from midnight GMT on January 1, 1970, in milliseconds. * /
    public long getLastAccessedTime(a);
    
    /** * Returns the current session's ServletContext */
    public ServletContext getServletContext(a);

    public void setMaxInactiveInterval(int interval);

    /** * Returns the maximum interval in which the Servlet container keeps session * open while the client accesses it */
    public int getMaxInactiveInterval(a);
    
    public HttpSessionContext getSessionContext(a);

    /** * Returns the object with the specified name in the session, or null if there is no object with the specified name. * /
    public Object getAttribute(String name);
    
    public Object getValue(String name);

    /** * Mandatory String Enumeration containing the names of all objects bound to the session * session. * /    
    public Enumeration<String> getAttributeNames(a);
    
    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);

    /** * indicates that the session session is invalid and unbinds any objects attached to it. * /
    public void invalidate(a);
    
    /** * This method returns true if the client does not know about the session, or if the client chooses not to participate in the session. * /
    public boolean isNew(a);
}
Copy the code

Create a session

The way to create a session is through request;

// create a Session object
HttpSession session = request.getSession(); 
// create a Session object
HttpSession session = request.getSession(true); 
Copy the code

These are the same; If a session does not exist, create a new one. If false, the identity returns NULL if it does not exist;

The life cycle

The life cycle of a session refers to the process from the creation of a session object in the Servlet container to its destruction. The Servlet container destroys the session object based on the session object’s lifetime. After a session is generated, the server updates the last access time of the session and maintains the session as long as the user continues to access the session.

Before, in single-process applications, SESSION was generally stored in memory, and I did not make persistent operations or use three-party services to store session information, such as Redis. However, in a distributed scenario, this approach in native memory is obviously not applicable because sessions cannot be shared. This one says later.

Session validity period

Sessions are generally stored in memory, which has certain limitations. Therefore, a session deletion mechanism must be adopted to ensure that session information does not accumulate for a long time to prevent memory overflow.

The session timeout period can be set by using the maxInactiveInterval property.

If we want to invalidate a session, we can do so by calling session invalidate().

Distributed session

First of all, why does this concept exist?

Consider this: my application now needs to be deployed on three machines. Is there a situation where THE first time I log in, I request to machine 1, and then I create a session on machine 1; But the second time I accessed it, the request was routed to machine 2, but machine 2 did not have my session information, so I had to log in again. Of course, this can be solved by nginx’s IP HASH load policy. The same IP request goes to the same machine.

But the business got bigger and bigger and bigger and bigger and bigger and bigger and bigger and bigger and bigger and bigger machines; Obviously that’s not going to work. At this time, we need to consider whether the session information should be placed on an independent machine. Therefore, the problem to be solved by distributed session is actually the problem of session sharing in distributed environment.

In the figure above, there are many ways to deploy a session independently, either as an independent database service, or as a cache service (Redis, currently the most common method, that is, using Redis as the session cache server).

reference

  • 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