How to store session information in the database for distributed architecture learning

Recently, I practiced a SpringCloud integrated registry, gateway, configuration center, and microservices. It happened that there were various problems with redis on the computer. I simply wrote a middleware without redis and stored it in MySQL. The following is a summary of the various problems encountered during the period.
Hands first introduce the basic implementation of this principle. I consulted the next master, and summed up a few points for persisting Session.

  1. Http is a stateless protocol;

The so-called http is a stateless protocol. The implication is that the http protocol cannot save client information, so it cannot distinguish the difference between each request. The server cannot distinguish whether the request sent through http comes from user A or user B. of. Statelessness about http hinders the implementation of interactive applications. For example, record which web pages the user browses, determine whether the user has permission to access, etc. As a result, two techniques for maintaining HTTP state came into being, one is Cookie, and the other is Session.

2. Fetch does not carry cookies by default;

fetch默认是不携带cookie到后台的,想要携带cookie必须
添加credentials: "include"这个设置;

fetch(url, {
              method: 'GET',
              headers: myHeaders,
              -->credentials: "include"<--
            })

这个时候服务端确实拿到了cookie,但是数据返回报错:
ERROR :Fetch API cannot load http://localhost:8077/sonny/l... The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8080' is therefore not allowed access.
这段鸟语翻译过来就是:当请求中的认证模式为‘include’时,响应的头部中的'Access-Control-Allow-Origin'不能设置为通配符“*”,这是因为cookie在设置的时候是不允许跨域的,如何在协达cookie的前后端分离项目中实现类似通配符”*“的功能将在下面讲述。因为报错了,因此得在后端添加:

response.setHeader(“Access-Control-Allow-Credentials”,”true”);
response.setHeader(“Access-Control-Allow-Origin”, “http://192.168.0.1“);

这样就解决了跨域传递session的问题。

3. Cookies are not allowed to cross domains;

Cookie class is not allowed to pass across domains. In addition to the solution above, Nginx can also be used;
nginx reverse proxy to solve cookie cross-domain problem

4. The browser obtains the server's support information for the request through the OPTION request;

The OPTIONS method is less common and is used to request the server to tell it what other functions and methods it supports. Through the OPTIONS method, you can ask the server which methods it supports, or what methods the server will use to handle some special resources. It can be said that this is a exploratory method by which the client can know the optimal way to handle the resource without accessing the actual resource on the server.

5. Since it is relatively rare, under what circumstances will the OPTION method be used?

When the sent request is a simple request, the server will automatically add an Origin field to the header of the response, and its value will be automatically set to the corresponding request domain. Origin: http://api.bob.comTherefore, it can be said that there is no cross-domain problem with simple requests. of.

A), what is a simple request?
Browsers divide CORS requests into two categories: simple requests and not-so-simple requests.


As long as the following two conditions are met at the same time, it is a simple request.
(1) The request method is one of the following three methods:
HEAD
GET
POST
(2) The HTTP header information does not exceed the following fields:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type: limited to three If the values ​​of application/x-www-form-urlencoded, multipart/form-data, and text/plain
do not meet the above two conditions at the same time, they belong to non-simple requests.
Browsers handle these two requests differently.


If the above two conditions are not met at the same time, it is a non-simple request. Browsers handle these two requests differently.

A non-simple request is a request that has special requirements on the server, such as the request method being PUT or DELETE, or the type of the Content-Type field being application/json.
For CORS requests that are not simple requests, an HTTP query request will be added before the formal communication, which is called a "preflight" request.
The browser first asks the server whether the domain name of the current page is on the server's allow list, and which HTTP verbs and header fields can be used. The browser will issue a formal XMLHttpRequest request only if it gets a positive answer, otherwise it will report an error.

Cross-domain resource sharing CORS detailed explanation

6. Session is identified by the information in Cookies;

When the problem of cross-domain and cookie carrying is solved, every time the browser sends a request, it will carry a cookie information, so how is the connection between Session and JSESessionId?

First we need to know when the Session was created?
How is sessionid generated? by whom? Where is it kept?


Of course, it is created during the running of the server-side program. Applications implemented in different languages ​​have different methods of creating a Session. In Java, they are created by calling the getSession method of HttpServletRequest (using true as a parameter). When the Session is created, the server will generate a unique Session id for the Session, and this Session id will be used to retrieve the created Session in subsequent requests; after the Session is created, you can call the Session-related The method adds content to the Session, and these content will only be stored in the server, and only the Session id will be sent to the client; when the client sends a request again, it will bring this Session id.


A session is saved for each user on the server, so how do you know which session a user should correspond to when a user requests it?


This is where jsessionid comes in handy. Each session has an id as an identifier, this id will be passed to the client, and every client request will pass this id to the server, and the server will match which session should be used for this request according to the id. jsessionid is the variable used by the client to save the sessionid, mainly for the web container implemented by j2ee. I haven't studied what variables are used in other languages ​​to save it. Generally, for web applications, client variables are stored in cookies, and jsessionid is no exception. However, unlike the general cookie variable, jsessionid is stored in the memory cookie, and its shadow cannot be seen in the general cookie file. Memory cookies are created when a browser window is opened and destroyed when the browser window is closed. This also explains why the session variable cannot be used across windows. To use it across windows, you need to manually save the jsessionid into the cookie.


See the code below:

package com.spring.boot.gp4zj.util;

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.ApplicationContext;

import com.spring.boot.gp4zj.model.UserSession;
import com.spring.boot.gp4zj.model.Worker;
import com.spring.boot.gp4zj.service.AuthenticationService;
import com.spring.boot.gp4zj.service.impl.AuthenticationServiceImpl;

import cn.lz.cloud.common.service.ReqObject;

/**
 * 我自己封装的session工具类;
 * @author xdsm
 *
 */
public class MySession {
     //私有的静态内部类保证了单例,并且是懒汉模式的;
    private static class SingletonHolder{
      private static final MySession INSTANCE = new MySession();
    }
    private MySession(){}

    public static final MySession getInstance(){
          return SingletonHolder.INSTANCE;
    }
    private ApplicationContext applicationContext = SpringUtils.getApplicationContext();
    private AuthenticationService authenticationService = applicationContext.getBean(AuthenticationServiceImpl.class);
    /**
     * 根据请求中携带的session信息获取用‘session’中的用户户信息;
     * @return
     */
  public Worker getAttributeOfUserInfo(HttpServletRequest request) {
      //获取jseSessionId;
      String jsessionid = HttpUtils.getJsessionidFromHeader(request);// 获取请求携带的sessioId;
      //查询用户信息;
      UserSession requestAttachmentInfo = new UserSession();
      requestAttachmentInfo.setJsessionid(jsessionid);
      ReqObject<UserSession> sessionSelecCondition = new ReqObject<UserSession>();
      sessionSelecCondition.setObject(requestAttachmentInfo);
      UserSession sessionVo = authenticationService.selectUserSessionBySessionID(sessionSelecCondition);
      Worker workerInfo = new Worker();
      String workerName = sessionVo.getWorkerName();
      String workerPassword = sessionVo.getWorkerPassword();
      workerInfo.setWorkerName(workerName);
      workerInfo.setWorkerPassword(workerPassword);
      Worker sessionAttruVO = authenticationService.doGetAuthenticationInfo(workerInfo);
    return sessionAttruVO;
  }

}

package com.spring.boot.gp4zj.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;

public class HttpUtils {
    public static void main(String[] args) {
        HttpServletResponse response = null;
        responseOutWithJson(response, null);
    }

    public static String getHostIp() {
        InetAddress addr;
        String currentIP = null;
        try {
            addr = InetAddress.getLocalHost();
            currentIP = addr.getHostAddress().toString(); //获取本机ip
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return currentIP;
    }

    public static void responseOutWithJson(HttpServletResponse response, Object responseObject) {
        // Person person=new Person();
        Gson gson = new Gson();
        // Object stu = new Student("ShaHao", 21);
        String objStrJson = gson.toJson(responseObject);
        // System.out.println(objStrJson);
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.print(objStrJson);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 获取post请求中的Body
     *
     * @param request
     * @return
     */
    public static String getBodyString(HttpServletRequest request) {
        System.out.println("--------HttpUtils---------HttpUtils--------");
        Enumeration<?> ele = request.getHeaderNames();
        while (ele.hasMoreElements()) {
            String name = (String) ele.nextElement();
            String value = request.getHeader(name);
            System.out.println(name + " = " + value);

        }

        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            // 读取流并将流写出去,避免数据流中断;
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /**
     * 从请求的头部获取用户的身份识别id;
     * 
     * @param request
     * @return
     */
    public static String getJsessionidFromHeader(HttpServletRequest request) {
        String jsessionid = null;// 识别用户身份的id;
        Enumeration<?> e = request.getHeaderNames();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            String value = request.getHeader(name);
            // cookie = JSESSIONID=B926F6024438D4C693A5E5881595160C;
            // SESSION=458e80dc-e354-4af3-a501-74504a873e70
            if ("cookie".equals(name)) {
                jsessionid = value.split(";")[0].split("=")[1];
            }
        }
        return jsessionid;
    }
}

In fact, all that is needed is to obtain a valid SessionId. The reference articles are all above, which combines my understanding and reference content, I hope it can help everyone.

write picture description here
It's summer, and it's time to grow meat again. . . . . .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324588787&siteId=291194637