Web Cookie与Session学习

Cookie

        Cookie是由服务端生成的,发送给客户端(通常是浏览器)的,保存在客户端中,并且是可见的,客户端的一些程序可能会篡改、窥探cookie中的内容。假如用到Cookie,比较好的方法是,敏感的信息如账号密码等尽量不要写到Cookie中。最好是像Google、Baidu那样将Cookie信息加密,提交到服务器后再进行解密,保证Cookie中的信息只要本人能读得懂。(选择Session就省事多了,反正是放在服务器上,Session里任何隐私都能够有效的保护)

按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie:

  1. 内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。
  2. 硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。

        登录过Google,Google的登录信息长期有效。用户不用每次访问都重新登录,Google会持久地记载该用户的登录信息。要到达这种效果,运用Cookie会是比较好的选择。只需要设置Cookie的过期时间属性为一个很大很大的数字。当用户第一次访问并登陆一个网站的时候,cookie的设置以及发送会经历以下4个步骤:

  1. 客户端发送一个请求到服务器 
  2. 服务器返回一个HttpResponse响应到客户端,其中设置了Set-Cookie的头部(可以在服务端设置cookie.setHttpOnly(true)设置响应头携带cookie信息)
  3.  客户端保存cookie,之后向服务器发送请求时,HttpRequest请求中会包含一个Cookie的头部
  4. 服务器返回响应数据
package com.cloud.ceres.rnp.control.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;


@RestController
@RequestMapping("/aop")
public class AopControl {
  
    private static Logger logger = LoggerFactory.getLogger (AopControl.class);

    @GetMapping("/queryXXX")
    public String queryXXX()  {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();
        Cookie[] cookies = request.getCookies();
        if (cookies!= null) {
            for (Cookie cookie : cookies) {
                System.out.println(cookie.getName() + ":[cooke]:" + cookie.getValue());
                cookie.setHttpOnly(true);
                response.addCookie(cookie);
            }
        }
        HttpSession session = request.getSession();
        System.out.println("sessionId:" + session.getId());
        Enumeration<String> attrs = session.getAttributeNames();
        while(attrs.hasMoreElements()){
            // 获取session键值
            String name = attrs.nextElement().toString();
            // 根据键值取session中的值
            Object vakue = session.getAttribute(name);
            System.out.println(name + ":[session]" + vakue);
        }
        return "aopTest方法结束";
    }

}

通过浏览器访问该接口

第一次访问:由于第一次是不存在cookie的,所以第一次访问控制台输出如下:

sessionId:5FCF280DDF6F28C70C178B1FCBF12A01

第二次访问:由于第一次访问,所以第一次访问控制台输出如下:

JSESSIONID:[cooke]:F9AF6D66D4BAC7B3033A5F29F838D033
sessionId:5FCF280DDF6F28C70C178B1FCBF12A01

        实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候(服务点自动会生成持久化保存在服务端),服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。

(一)Cookie的根本作用就是在客户端存储用户访问网站的一些信息。典型的应用有:

1、记住密码,下次自动登录。

2、购物车功能。

3、记录用户浏览数据,进行商品(广告)推荐。

(二)缺陷

①Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。

②由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用HTTPS)

③Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。

参考:https://www.jianshu.com/p/6fc9cea6daa2

Session        

        在说session是啥之前,我们先来说说为什么会出现session会话,它出现的机理是什么?我们知道,我们用浏览器打开一个网页,用到的是HTTP协议,学过计算机的应该都知道这个协议,它是无状态的,什么是无状态呢?就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的。但是这种无状态的的好处是快速。

        所以就会带来一个问题就是,我希望几个请求的页面要有关联,比如:我在a.html里面登陆了,我在b.html 也希望是登陆状态,但是,这是2个不同的页面,也就是2个不同的HTTP请求,这2个HTTP请求是无状态的,也就是无关联的,所以无法单纯的在a.html中读取到它在b.html中已经登陆了!那咋搞呢?我不可能这2个页面我都去登陆一遍吧。或者用笨方法这2个页面都去查询数据库,如果有登陆状态,就判断是登陆的了。这种查询数据库的方案虽然可行,但是每次都要去查询数据库不是个事,会造成数据库的压力。

        所以正是这种诉求,这个时候,一个新的客户端存储数据方式出现了:cookie。cookie是把少量的信息存储在用户自己的电脑上,它在一个域名下是一个全局的,只要设置它的存储路径在域名www.a.com下 ,那么当用户用浏览器访问时,就可以从这个域名的任意页面读取cookie中的信息。所以就很好的解决了我在b.html页面登陆了,b.html获取到这个登陆信息了。同时又不用反复去查询数据库。虽然这种方案很不错,也很快速方便,但是由于cookie 是存在用户端,而且它本身存储的尺寸大小也有限,最关键是用户可以是可见的(密码一般不会存于cookie),并可以随意的修改,很不安全。那如何又要安全,又可以方便的全局读取信息呢?于是,这个时候,一种新的存储会话机制:session 诞生了

        session的全部机制也是基于这个session_id,它用来区分哪几次请求是一个人发出的。为什么要这样呢?因为HTTP是无状态无关联的,一个页面可能会被成百上千人访问,而且每个人的用户名是不一样的,那么服务器如何区分这次是小王访问的,那次是小李访问的呢?所以就有了找个唯一的session_id 来绑定一个用户。一个用户在一次会话上就是一个session_id,这样成千上万的人访问,服务器也能区分到底是谁在访问了。

        每次我们访问一个页面,默认会自动生成一个session_id 来标注是这次会话的唯一ID,同时也会自动往cookie里写入一个名字为JSESESSID的变量(tomcat生成取名为jseSessionId),它的值正是session_id,当这次会话没结束,再次访问的时候,服务器会去读取这个JSESESSID的cookie是否有值有没过期,如果能够读取到,则继续用这个session_id,如果没有,就会新生成一个session_id,同时生成JSESESSID这个cookie。由于默认生成的这个JSESESSID cookie是会话,也就是说关闭浏览器就会过期掉,所以,下次重新浏览时,会重新生成一个session_id。

        好,这个是session_id,就用来标识绑定一个用户的,既然session_id生成了。那么当我们往session里面写入数据即可。session是如何保存的?Tomcat保存session的方式是服务器端的内存中。对于PHP而言是保存在文件中。上述有提及。

(一)存储用户信息,典型的应用有:

1、购物车功能。(每次加入购物车携带session_id传入到服务器,然后在比较服务器中的session_id(此时一定要session共享),然后重新put新的list到对应的购物车集合中去)

2、登陆状态(将session存于redis,给其设置过期时间,如果过期了则视为离线,需重新登陆)

(二)缺陷

①Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。

②由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用HTTPS)

③Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。

备注

  1. 除了上述提及的方法外,解决session共享问题还有这样一种方式:(实质上并不是通过session的共享来解决的)这里以nginx为例,将用户请求分发到了不同机器上,那么我们只需要固定,同一用户请求分发到同一机器上进行处理,即这一次用户来请求服务器了,那么下一次它再来的时候,同样也请求也被分发到与上一次相同的服务器。这样就确保了同一用户不会因为请求分发到不同机器上而获取不到session数据的问题了。
  2. 从浏览器打开访问了某一个网站,关闭浏览器。这样的操作我们算一次“会话”。所以大部分就会认为用户访问了网站就会产生session ID。实际上不然。例如:在Java中我们需要调用HttpServletRequest的getSession方法创建session。而在PHP中需要session_start()一下,服务器才会将存有session ID的cookie回传回去。否则不会有什么session产生。
  3. session不会因为浏览器的关闭而删除。但是存有session ID的cookie的默认过期时间是会话级别。也就是用户关闭了浏览器,那么存储在客户端的session ID便会丢失,但是存储在服务器端的session数据并不会被立即删除。从客户端即浏览器看来,好像session被删除了一样(因为我们丢失了session ID,找不到原来的session数据了)。

疑问?

        当用户关闭浏览器后,该cookie应该就会自动销毁的。下次用户再次访问该网页,该cookie应该是不复存在了。但是谷歌浏览器关闭后,这个PHPSESSID 还存在呢? 比较疑惑,在火狐和IE都测试过,没有这样的问题???

参考:https://blog.csdn.net/qq_15096707/article/details/74012116

          https://www.cnblogs.com/isme-zjh/p/11359557.html

          https://www.zhihu.com/question/19786827/answer/28752144
 

获取cookie与session

        目前我们项目大多数是基于Spring框架的,所以获取它只需要拿到HttpServletRequest这个类即可,这个类里面可以从中拿到前台的cookie 和 服务器的 session(sessionId) 以及传入参数

1、RequestContextHolder(org.springframework.web.context.request.RequestContextHolder)

ServletRequestAttributes requestAttributes = (ServletRequestAttributes)                     RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
Cookie[] cookies = request.getCookies();
HttpSession session = request.getSession();
System.out.println("sessionId:" + session.getId());
Enumeration<String> attrs = session.getAttributeNames();
while(attrs.hasMoreElements()){
   // 获取session键值
   String name = attrs.nextElement().toString();
   // 根据键值取session中的值
   Object vakue = session.getAttribute(name);
   System.out.println("------" + name + ":" + vakue +"--------\n");
}

2、ServletActionContextcom.opensymphony.webwork.ServletActionContext)             

 HttpServletRequest request2 =ServletActionContext.getRequest();
 HttpSession session2 = request.getSession();
发布了74 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40826106/article/details/104073762
今日推荐