不积跬步,无以至千里

Session相关


做web开发不可避免会涉及到cookie和session,http的请求是无状态的,这里总结下平时梳理的关于cookie和session的相关知识.

Http是无状态的协议,现在的web应用越来越复杂,在每次的网络请求中,需要能够携带一些用户信息.最常见的是登录网站的时候,登录之后再次访问网站,服务器端需要知道这个用户是否是登录状态.于是就有了cookie和Session. cookie存储在客户端,用来保存会话信息,每次请求服务器端的时候会携带cookie请求,服务器端从cookie中获取到状态信息 而Session则由服务器端产生并保存在服务器端,服务器端从cookie中取到状态信息之后,需要针对这些信息做验证,这个验证信息就来自于服务器端的Session.

cookie

cookie的写入

cookie由服务端写入,cookie本身是一个字符串,但这个字符串是有格式的,有键值对组成. 如下是一个请求中的header信息:

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,zh;q=0.7,zh-CN;q=0.6
Connection: keep-alive
Cookie: _ga=GA1.2.486261727.1542307321; _gid=GA1.2.414078029.1542595624; s.k=n8-121-175c472a34a-f1bf-45c6-916a-4d8b7121422b; _gat=1
Host: www.baidu.com
Referer: https://www.baidu.com/page/approval-hub/user-permission
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36

每个cookie都有自己的属性,包括Domain,Path,ExpireTime,Size等,在设置cookie时可以设置这些属性

cookie的传递

客户端向服务端发起请求时,会先检查本地是否存在该域名下的cookie,如果存在,则将cookie加入到请求header中.一个URL包含域名(domain)和路径(path),这两个选项决定cookie是否要添加到header中.如果cookie在写入的时候未设置域名和路径,那么domain的默认值将是设置这个cookie的网页所在的域名,path默认为设置这个cookie的网页所在的目录.

跨域的cookie传递

session

Java应用中的Session实现

web应用运行在servlet容器中,servlet就是处理web请求的.Session对应的java实现类为HttpSession.Servlet容器通过HttpSession接口来实现Http客户端和Http服务端的Session. HttpServletRequest是HTTP servlet的请求实体类,由servlet容器创建.通过HttpServletRequest.getSession(boolean create);可以获得当前请求关联的Session,如果不存在Session,则创建一个. 在Tomcat中,ApplicationHttpRequest是HttpServletRequest的包装类.StandardSessionFacade则是HttpSession的实现类.其中getSession的实现如下:

    /**
     * Return the session associated with this Request, creating one
     * if necessary and requested.
     *
     * @param create Create a new session if one does not exist
     */
    @Override
    public HttpSession getSession(boolean create) {

        if (crossContext) {//标示web应用的路径是否一样

            // There cannot be a session if no context has been assigned yet
            if (context == null)
                return null;

            // Return the current session if it exists and is valid
            if (session != null && session.isValid()) {
                return session.getSession();
            }

            HttpSession other = super.getSession(false);
            if (create && (other == null)) {
                // First create a session in the first context: the problem is
                // that the top level request is the only one which can
                // create the cookie safely
                other = super.getSession(true);
            }
            if (other != null) {
                Session localSession = null;
                try {
                    localSession =
                        context.getManager().findSession(other.getId());//根据sessionId获取上下文中的HttpSession
                    if (localSession != null && !localSession.isValid()) {
                        localSession = null;//若本地session过期,则置为null
                    }
                } catch (IOException e) {
                    // Ignore
                }
                if (localSession == null && create) {
                    localSession =
                        context.getManager().createSession(other.getId());//若本地session不可用,根据指定的sessionid创建一个新的session
                }
                if (localSession != null) {
                    localSession.access();
                    session = localSession;
                    return session.getSession();
                }
            }
            return null;

        } else {
            return super.getSession(create);
        }

    }

分布式Session管理

现在的服务器基本都是分布式系统,也就是说,一个应用会同时部署在多台机器上,根据负载均衡策略的不同,一个用户的请求可能会发送到不同的服务器上,那么就带来了一个问题:如果Session存储在服务器,当一个用户的请求被分发到不同的服务器上时,两次的请求在服务器端的状态信息就会存在不一致的情况.对于需要验证登录信息的页面,就会导致用户反复登录. 所以现在的系统设计需要对Session信息做集中管理,独立于web容器. 在Spring框架下,这个问题有一个很好的解决方案~:spring-session

todo:spring-session实现

参考: Session机制详解以及Session的相关应用 spring-session文档 聊一聊 cookie cookie知识点整理 cookie的domain写入(指定的时候/默认值) cookie的各个属性值和含义 服务端和客户端设置cookie cookie的修改和删除 跨域设置cookie xhr cors–跨域cookie的传递 怎样跨域传递cookie?怎样算跨域

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain 定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件 application/x-www-form-urlencoded form表单被编码为key/value格式发送到服务器 multipart/form-data 需要在表单中进行文件上传时,就需要使用该格式 application/json;charset=UTF-8 数据以json格式传输

http body和request