Cookie 和 Session的使用和理解

一、概述

最近想尝试写一个关于网络请求的系列文章,将网络请求的基础、使用及网络框架的学习分析总结以下,大致准备从以下几个方面分析:

  1. 网络请求的基础
  2. HTTP请求方式和报文解析
  3. Cookie 和 Session的理解与使用
  4. HTTP Cache缓存机制
  5. 封装网络请求
  6. TCP 和 Socket

本文主要介绍Cookie和Session的使用和理解,先讲讲为什么会使用Cookie 和Session?大家都知道Http是基于TCP协议传输信息的,但不同于TCP的是Http协议是短链接,即当请求完成后会中断链接,这样就会产生一个问题,当用户每次请求时之间都会间隔一段时间或者在登陆之后就不再操作,那么当下次想请求数据时,发送Request到服务器,但服务器此时不知道是谁在请求,也不知道该回应谁,所以此时就出现用户的操作执行不下去了;这时就是Cookie和Session的登场了,他们的作用就是保证服务器可以知道每个请求客户端的身份,下面我们一一介绍。

二、Cookie

  • Cookie技术是客户端的解决方案:服务器在用户登陆后会按照一定规律生成的标志位,将这个标志发送给客户端,客户端存储此标志,以后请求带上此标志告诉服务器自己的身份,对于这个的理解更直观的例子就是身份证,如果把国家比喻服务器,自己必做客户端,每个人在登记户口后都可以办理身份证,身份证是由国家颁发自己保存也就是Cookie,以后无论你在何时何地只要你拿出身份证就代表你身份,当你去办理车票等信息时只需出事身份证就可证明自己;
  • cookie的内容主要包括:名字,值,过期时间,路径和域
  • 客户端提交个人信息后,服务端返回数据的同时会在Response Header中返回Cookie信息,客户端保存在固定的位置(Set-Cookie: 设置 返回的Cookie)
  • 客户端在下次请求的时候会在Request Header中携带Cookie信息,服务端根据Cookie确认用户身份(如:自动登陆)(Cookie: 设置上传携带的Cookie)
  • cookie的设置以及发送过程分为以下四步

  1. 客户端发送一个http请求到服务器端
  2. 服务器端发送一个http响应到客户端,其中包含Set-Cookie头部
  3. 客户端发送一个http请求到服务器端,其中包含Cookie头部
  4. 服务器端发送一个http响应到客户端
  • Cookie有效期:由maxAge决定,在服务器返回cookie时已设置号对应的时间
  1. 正数:表示有效期 时间为 maxAge,需;序列化在磁盘中,超过时间失效
  2. 负数:临时Cookie 不序列化,保存在内存中,关闭浏览器失效
  3. 0 :表示删除该Cookie
  • Cookie的修改、删除
  1. 修改:创建同名的Cookie在Response中返回,覆盖原来的
  2. 删除:创建同名的Cookie,设置maxAge = 0,在Response中返回
  • Cookie域名
  1. Cookie不可跨域名操作,每个域名只能操作自己的Cookie文件,客户端获取Cookie:
CookieStore mCookieStore = httpclient.getCookieStore();
List<Cookie> cookies = mCookieStore.getCookies();
  • Cookie的使用(以百度网页为例)
  1. 登陆百度时,服务器返回的ResponseHeader中会是返回生成的Cookie

      2、在下次请求时,会携带Cookie

三、Session

  • 简介

Session技术则是服务端的解决方案,通过服务器来保持状态;当客户端第一次请求时服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,发送给客户端,客户端储存,客户端再次发送请求的时候,会将这个Session id带上,服务器根据SessionID查找用户身份

  • Session原理:服务端端每一个session维护一份会话信息数据,客户端和服务端依靠一个全局唯一标识sesssion_id来访问会话信息数据
  • Session创建:server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建
  • session的保存
  1. Cookie:一般采用Cookie保存sessionId,这样下次请求时会自定添加到Request Header,cookie的名字都是类似于SEEESIONID,比如weblogic对于web应用程序生成的cookie,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是JSESSIONID
  2. URL重写(cookie被禁止):在客户端禁止Cookie时,Cookie就无法保存SessionId和发送了,此时可以使用其他方法解决:把sessionId直接附加在URL的路径之后:http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764; 作为字符串附加在请求中:http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
  • 与Cookie对比
    1. cookie:信息保存在本地容易被第三方或其他获取,发起恶意请求
    2. session:信息保存在服务端的内存中,本地只使用cookie保存sessionId
  • sessionId的时效
  1. 服务器会设置时间限定,当超过限定时间后还收不到客户端的请求即认为失效,session会结束生命周期,此时需要重新登陆
  2. 没有储存在数据库的Session,会在服务器重启后失效
  3. 用户退出登陆的时候会发起删除session,此时服务器会删除session
  • 防止session混乱
  1. 通过设置客户端的令牌来解决;在服务器每次生成一个不同的id返回给客户端,同时保存在session里,客户端提交表单时必须把这个id也返回服务器,程序首先比较返回的id与保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了
  • Session使用

四、Android中Cookie的使用

  • okHttp3 简化了Cookie的使用
cookieJar(new ...)  //  创建OkHttp时只需设置 cookieJar的对象,即可自动实现Cookie功能
  • CookieJar:Cookie策略,接口的实现负责选择要接受哪些cookie和拒绝哪些Cookie,两个抽象方法:
void saveFromResponse(HttpUrl url, List<Cookie> cookies);  // 从Response中保存Cookie
List<Cookie> loadForRequest(HttpUrl url); // 为请求的url 查找Cookie,返回Cookie集合
  • saveFromResponse():保存Cookie
if (cookies != null && cookies.size() > 0) {
    for (Cookie item : cookies) {
        cookieStore.add(url, item);
    }
}

public void add(HttpUrl url, Cookie cookie) {
    String name = getCookieToken(cookie);  // 按照一定规则生成相应的Key

    //将cookies缓存到内存中 如果缓存过期 就重置此cookie
    if (!cookie.persistent()) { 判断是否失效;true:未失效;false:失效
        if (!cookies.containsKey(url.host())) {
            cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>()); // 以host为键,在HashMap中创建保存本次Cookie的Map
        }
        cookies.get(url.host()).put(name, cookie);  // 将 key 和 cookie 放入到Map中
    } else {
        if (cookies.containsKey(url.host())) {
            cookies.get(url.host()).remove(name);  // 移除cookie
        }
    }

    //讲cookies持久化到本地
    SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
    prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));  
// TextUtils.join:遍历Iterate每个元素以“,”分割拼接成String
// 将ConcurrentHashMap的Key序列化在本地,以逗号隔开
    prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie))); 
// 以name为键保存Cookie信息
    prefsWriter.apply();
}
  •  cookieStore 和 cookies
public PersistentCookieStore(Context context) {  // 初始化PersistentCookieStore并将Cookie加载进内存中
    cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
    cookies = new HashMap<>();

    //将持久化的cookies缓存到内存中 即map cookies
    Map<String, ?> prefsMap = cookiePrefs.getAll();  // 以Map的形式返回所有储存信息
    for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
        String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");  // 取出储存的每个Key
        for (String name : cookieNames) {
            String encodedCookie = cookiePrefs.getString(name, null);  // 获取保存的Cookie信息
            if (encodedCookie != null) {
                Cookie decodedCookie = decodeCookie(encodedCookie); // 转换为Cookie 
                if (decodedCookie != null) {
                    if (!cookies.containsKey(entry.getKey())) {
                        cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>());
                    }
                    cookies.get(entry.getKey()).put(name, decodedCookie);
                }
            }
        }
    }
}
  • cookie 与 String 间的解析
/**
* cookies 序列化成 string
*/
protected String encodeCookie(OkHttpCookies cookie) {
    if (cookie == null)
        return null;
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    try {
        ObjectOutputStream outputStream = new ObjectOutputStream(os);
        outputStream.writeObject(cookie);
    } catch (IOException e) {
        Log.d(LOG_TAG, "IOException in encodeCookie", e);
        return null;
    }

    return byteArrayToHexString(os.toByteArray());  // 将字节转换为16进制字符串
}

/**
* 将字符串反序列化成cookies
*/
protected Cookie decodeCookie(String cookieString) {
    byte[] bytes = hexStringToByteArray(cookieString); // 将字符串转换为字节数组
    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
    Cookie cookie = null;
    try {
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        cookie = ((OkHttpCookies) objectInputStream.readObject()).getCookies();
    } catch (IOException e) {
        Log.d(LOG_TAG, "IOException in decodeCookie", e);
    } catch (ClassNotFoundException e) {
        Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);
    }
    return cookie;
}
  • 使用上述设置的Cookie请求信息:
  1. 第一次使用账号密码请求登陆,请求Header和Body

  2、此时服务端验证密码后登陆成功,机会返回带有Cookie信息的Response

 3、客户端收到Cookie后,会储存Cookie信息,查看保存的信息如下:

可以看出Cookie中保存了name = “JSESSIONID”和Value = “95843******”的Cookie信息

  • 再次请求时携带Cookie

  • 1
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

Alex@W

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值