zoukankan      html  css  js  c++  java
  • java之Cookie和Session

    一、会话

    1、会话:一次会话中包含多次请求和响应。

    • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止

    2、功能:

    • 在一次会话的范围内的多次请求间,共享数据

    3、方式:

    客户端会话技术:Cookie
    服务器端会话技术:Session

    4、http协议无状态

    状态的含义:

    客户端域服务器在某次会话中产生的数据,这些数据存在于缓存区中,缓存区中存储、记忆、共享一些临时数据,从而无状态就意味着,这些数据不会被保留。

    无状态的官方解释:

    1. 协议对于事务处理没有记忆能力
    2. 对同一个url请求没有上下文关系
    3. 每次的请求都是独立的,它的执行情况和结果与之前的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
    4. 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器。

    但是,通过增加cookie和session机制,现在的网络请求其实是有状态的。
    在没有状态的http协议下,服务器也一定会保留你每次网络请求对数据的修改,但这跟保留每次访问的数据是不一样的,保留的只是会话产生的结果,而没有保留会话。

    举例思考:

    假如没有cookie没有session,http无状态的时候,当一个用户访问网站的时候,会有下面的问题:
    你每访问一次需要权限的内容都需要在客户端输入用户名和密码。
    你的每一次操作都要与系统底层的数据库进行交互(多次少量的访问存在非常大的性能浪费。非常容易就能想到肯定是一次大量的操作更有效率,于是就想到了缓存区)
    你的非重要琐碎数据也被写进数据库中,跟你的主要数据放在一起(一次次添加和删除购物车只是跟你这次浏览,或者叫这次会话有关,是临时的数据,跟用户的主要信息无关,它们没什么价值,纯粹的冗余数据,用什么存放这些临时的数据,我们也很容易想到缓存区。)
    上面就是无状态时候,会出现的问题,即使有连接,也无法解决【每一次操作都要与系统底层的数据交互】的问题,要解决【每一次操作都要与系统底层的数据库进行交互】就必须在服务端开辟一块缓存区。

    二、cookie

    1、概念:

    客户端会话技术,服务端给客户端的数据,存储于客户端(浏览器)。由于是保存在客户端上的,所以存在安全问题,并且cookie是由个数和大小限制的(4KB),所以一般cookie用来存储一些比较小且安全性要求不高的数据,而且一般数据都会进行加密。

    我们平时在登录某些网站时,关闭浏览器后再次打开登录,用户名密码等数据会自动填充在表单。
    或者我们浏览淘宝的某个商品后,下次再打开发现出现的商品很多都是我们之前浏览的同类商品等。
    这些都是cookie的应用场景。

    2、快速入门

    使用步骤:
    创建Cookie对象,绑定数据
    new Cookie(String name, String value)
    发送Cookie对象
    response.addCookie(Cookie cookie)
    获取Cookie,拿到数据
    Cookie[] request.getCookies()

    3、实现原理

    基于响应头set-cookie和请求头cookie实现

    4、cookie的细节

    1.一次可不可以发送多个cookie?

    • 可以
    • 可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可。

    2.cookie在浏览器中保存多长时间?

    默认情况下在浏览器关闭后就会失效。即一次会话后就失效。因为cookie是放在浏览器缓存的,浏览器关闭会清除缓存所以cookie会失效。

    要想使这个cookie在浏览器关闭后仍然有效就需要设置有效时间将其写到磁盘下。

    持久化存储:

      setMaxAge(int seconds)
        正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
        负数:默认值
        零:删除cookie信息
    3.cookie能不能存中文?

    1. 在tomcat 8 之前 cookie中不能直接存储中文数据。

        需要将中文数据转码---一般采用URL编码(%E3)

    1. 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析

    4.cookie共享问题?

    4、1假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?

    1. 默认情况下cookie不能共享
    2. setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
    3. 如果要共享,则可以将path设置为"/"

    4、2不同的tomcat服务器间cookie共享问题?

    1. setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
    2. setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享

    5、Cookie的特点和作用

    cookie存储数据在客户端浏览器
    浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)

    作用:

    cookie一般用于存出少量的不太敏感的数据
    在不登录的情况下,完成服务器对客户端的身份识别

    6、Cookie的生命周期

    Cookie也是一个类,我们需要关注一下它什么时候生成什么时候消亡。这样我们才能更好的确定何时获取Cookie
    Cookie的出生

    当执行完这句代码的时候就代表这个Cookie诞生
    Cookie cookie = new Cookie(String name,String value);

    Cookie的消亡

    默认情况下,在你关闭客户端后Cookie就会消失。此时你去获取cookie会返回null
    如果设置了有效时间后则需要在有效时间到期后才会消亡。

    7、代码示例

    package com.stuwork.crowdfunding.controller;
    
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.stuwork.crowdfunding.bean.Member;
    import com.stuwork.crowdfunding.bean.Permission;
    import com.stuwork.crowdfunding.bean.User;
    import com.stuwork.crowdfunding.manager.service.UserService;
    import com.stuwork.crowdfunding.potal.service.MemberService;
    import com.stuwork.crowdfunding.util.AjaxResult;
    import com.stuwork.crowdfunding.util.ConstUtil;
    import com.stuwork.crowdfunding.util.MD5Util;
    
    @Controller
    public class DispatcherController {
    
        @Autowired
        private UserService userService;
        
        @Autowired
        private MemberService memberService;
        //跳转到web-inf的index页面。
        @RequestMapping("/index")
        public String index (){
            return "index";
        }
        //跳转到登录页面
        @RequestMapping("/login")
        public String login(HttpServletRequest request,HttpSession session){
            //判断是否需要自动登录
            //如果之前登录过,cookie中存放了用户信息,需要获取cookie中的信息,并进行数据库的验证
            
            boolean needLogin = true;
            String logintype = null ;
            Cookie[] cookies = request.getCookies();
            if(cookies != null){ //如果客户端禁用了Cookie,那么无法获取Cookie信息
                
                for (Cookie cookie : cookies) {
                    if("logincode".equals(cookie.getName())){
                        String logincode = cookie.getValue();
                        System.out.println("获取到Cookie中的键值对"+cookie.getName()+"===== " + logincode);
                        //loginacct=admin&userpwd=21232f297a57a5a743894a0e4a801fc3&logintype=1
                        String[] split = logincode.split("&");
                        if(split.length == 3){
                            String loginacct = split[0].split("=")[1];
                            String userpwd = split[1].split("=")[1];
                            logintype = split[2].split("=")[1];
                            Map<String, String> mapParam = new HashMap<String, String>();
                            mapParam.put("loginacct", loginacct);
                            mapParam.put("userpswd", userpwd);
                            mapParam.put("type", logintype);
                            if("user".equals(logintype)){
                                
                                User dbLogin = userService.getUserInfo(mapParam);
                                
                                if(dbLogin!=null){
                                    session.setAttribute(ConstUtil.LOGIN_USER, dbLogin);
                                    needLogin = false ;
                                }
                                //----------------------------------
                                List<Permission> permissionList = userService.getUserRolePermissionByUserId(dbLogin.getId());
                                Permission permissionRoot = null;
                                Set<String> uris = new HashSet<String>();
                                Map<Integer,Permission> map = new HashMap<Integer,Permission>();
                                for(Permission bean :permissionList){
                                    map.put(bean.getId(), bean);
                                    uris.add("/"+bean.getUrl());
                                }
                                for(Permission bean :permissionList){
                                    Permission children = bean;
                                    if(bean.getPid() == 0){
                                        permissionRoot = bean;
                                    }else{
                                        Permission parent = map.get(children.getPid());
                                        parent.getChildren().add(children);     
                                    }
                                }
                                session.setAttribute(ConstUtil.PERMISSION_ROOT, permissionRoot);
                                session.setAttribute(ConstUtil.URIS, uris);
                                //----------------------------------
                            }else if("member".equals(logintype)){
                                Member dbLogin = memberService.getMemberInfo(mapParam);
                                
                                if(dbLogin!=null){
                                    session.setAttribute(ConstUtil.LOGIN_MEMBER, dbLogin);
                                    needLogin = false ;
                                }
                            }
                            
                        }
                    }
                }
            }
            
            if(needLogin){
                return "login";
            }else{
                if("user".equals(logintype)){
                    return "redirect:/main.htm";
                }else if("member".equals(logintype)){
                    return "redirect:/member.htm";
                }
           }
           return "login";
        }
        //@RequestParam里的value必须是前端页面name熟悉的值,login可以接收到值(和name属性值一样也可以),否则接收不到
        //同步请求
        /*@RequestMapping("/doLogin")
        public String doLogin(@RequestParam(value="loginacct") String login,
               String userpswd,String type,HttpSession session){
            Map<String, String> map = new HashMap<String, String>();
            map.put("loginacct", login);
            map.put("userpswd", userpswd);
            map.put("type", type);
            
            User user = userService.getUserInfo(map);
            session.setAttribute(ConstUtil.LOGIN_USER, user);
            
            //重定向到主页面,不直接返回main,是防止刷新页面重复提交表单
            return "redirect:/main.htm";
            
        }*/
        //异步请求
        @ResponseBody
        @RequestMapping("/doLogin")
        public Object doLogin(@RequestParam(value="loginacct") String login,
                              String userpswd,
                              String type,
                              boolean rememberMe,
                              HttpSession session,
                              HttpServletResponse response){
            AjaxResult result = new AjaxResult();
            Map<String, String> mapParam = new HashMap<String, String>();
            mapParam.put("loginacct", login);
            mapParam.put("userpswd", MD5Util.digest(userpswd));
            mapParam.put("type", type);
            try {
    
                if("member".equals(type)){
                    Member member = memberService.getMemberInfo(mapParam);
                    session.setAttribute(ConstUtil.LOGIN_MEMBER, member);
                    if(rememberMe){
                        String logincode = ""loginacct="+member.getLoginacct()+"&userpwd="+member.getUserpswd()+"&logintype=member"";
                        //loginacct=admin&userpwd=21232f297a57a5a743894a0e4a801fc3&logintype=1
                        System.out.println("用户-存放到Cookie中的键值对:logincode::::::::::::"+logincode);
                        Cookie c = new Cookie("logincode",logincode);
                        
                        c.setMaxAge(60*60*24*14); //2周时间Cookie过期     单位秒
                        c.setPath("/"); //表示任何请求路径都可以访问Cookie
                        
                        response.addCookie(c);
                    }
                }else{
                    User user = userService.getUserInfo(mapParam);
                    session.setAttribute(ConstUtil.LOGIN_USER, user);
                    if(rememberMe){
                        //服务器向客户端写Cookie时含有特殊符号,Tomcat7不需要增加双引号;Tomcat6需要增加双引号;
                        //否则将来服务器端可能读取不到Cookie值(logincode串)
                        String logincode = ""loginacct="+user.getLoginacct()+"&userpwd="+
                                           user.getUserpswd()+"&logintype=user"";
                        //loginacct=admin&userpwd=21232f297a57a5a743894a0e4a801fc3&logintype=1
                        System.out.println("用户-存放到Cookie中的键值对:logincode::::::::::::"+logincode);
                        Cookie c = new Cookie("logincode",logincode);
                        
                        c.setMaxAge(60*60*24*14); //2周时间Cookie过期     单位秒
                        c.setPath("/"); //表示任何请求路径都可以访问Cookie
                        
                        response.addCookie(c);
                    }
                    //----------------------------------
                    List<Permission> permissionList = userService.getUserRolePermissionByUserId(user.getId());
                    Permission permissionRoot = null;
                    Set<String> uris = new HashSet<String>();
                    Map<Integer,Permission> map = new HashMap<Integer,Permission>();
                    for(Permission bean :permissionList){
                        map.put(bean.getId(), bean);
                        uris.add("/"+bean.getUrl());
                    }
                    for(Permission bean :permissionList){
                        Permission children = bean;
                        if(bean.getPid() == 0){
                            permissionRoot = bean;
                        }else{
                            Permission parent = map.get(children.getPid());
                            parent.getChildren().add(children);     
                        }
                    }
                    session.setAttribute(ConstUtil.PERMISSION_ROOT, permissionRoot);
                    session.setAttribute(ConstUtil.URIS, uris);
                    //----------------------------------
                }
                result.setData(type);
                result.setSuccess(true);
            } catch (Exception e) {
                
                e.printStackTrace();
                result.setMessage("登录失败!");
                result.setSuccess(false);
            }
                     
            return result;
            
        }
        //跳转到主页面
        @RequestMapping("/main")
        public String main(HttpSession session){
    
            return "main";
        }
        //跳转到主页面
        @RequestMapping("/member")
        public String member(HttpSession session){
            return "member/index";
        }
        //跳转到首页
        @RequestMapping("/logout")
        public String logout(HttpSession session){
            session.invalidate();//销毁session对象
            return "redirect:/index.htm";
        }
    }

    三、session

    1、概念

    服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession

    2、快速入门

    1. 获取HttpSession对象

    HttpSession session = request.getSession();

    2. 使用HttpSession对象:

    Object getAttribute(String name)
    void setAttribute(String name, Object value)
    void removeAttribute(String name)

    3、 原理

    • Session的实现是依赖于Cookie的。
    • cookie中有JSESSIONID这个字段,实际上首次请求网页时在请求头里是没有这个字段的,因为我们并没有创建session,当我们调用request.getSession()时,此时会创建一个session,并且将sessionId保存到cookie中,然后回写给response,所以我们发现首次创建session时的响应头中有JSESSIONID这个字段,后面的request默认都会带上JSESSIONID这个字段,而response中则不会再有该字段了。而服务器就能够根据JSESSIONID这个字段值查找对应的session。
    • 如果浏览器禁用了cookie,那么,每次请求都会重新创建session,因为服务器没有获取到JSESSIONID这个值,也无法根据JSESSIONID的值查找相应的session,也就是说,如果客户端禁用了cookie,那么,每次请求得到的sessionId是不一样的。

    4、细节

    1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
            * 默认情况下。不是。
            * 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
                 Cookie c = new Cookie("JSESSIONID",session.getId());
                 c.setMaxAge(60*60);
                 response.addCookie(c);
    
        2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
            * 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
                * session的钝化:
                    * 在服务器正常关闭之前,将session对象系列化到硬盘上
                * session的活化:
                    * 在服务器启动后,将session文件转化为内存中的session对象即可。
                
        3. session什么时候被销毁?
            1. 服务器关闭
            2. session对象调用invalidate() 。
            3. session默认失效时间 30分钟
                选择性配置修改    
                <session-config>
                    <session-timeout>30</session-timeout>
                </session-config>

    5、session的特点

    1. session用于存储一次会话的多次请求的数据,存在服务器端
    2. session可以存储任意类型,任意大小的数据

    6、session的创建和关闭

    • Session创建:在你打开一个浏览器开始访问的时候,就创建了。
    • Session关闭:他在你关闭浏览器的时候或者默认时间(Tomcat是30分钟)后会销毁。

    7、session与Cookie的区别:

    1. session存储数据在服务器端,Cookie在客户端
    2. session没有数据大小限制,Cookie有
    3. session数据安全,Cookie相对于不安全

     

  • 相关阅读:
    Apache Spark源码走读之8 -- Spark on Yarn
    Apache Spark源码走读之7 -- Standalone部署方式分析
    Apache Spark源码走读之6 -- 存储子系统分析
    Linux服务器--所有用户登陆操作命令审计
    Linux--top命令查看系统状态,所有值讲解
    docker --help 详解
    Linux下使用《du》命令查看某文件及目录的大小
    Linux查看CPU《型号..》《内存..》《硬盘..》《系统..》
    Linux下 cmatrix的安装和使用
    CentOS 6.3下部署LVS(NAT)+keepalived实现高性能高可用负载均衡
  • 原文地址:https://www.cnblogs.com/konglxblog/p/15322178.html
Copyright © 2011-2022 走看看