学习链接

理解cookie、session、localStorage、sessionStorage的关系与区别
session共享原理 - 自己的链接
Cookie详解

cookie

什么是cookie?

由于HTTP是一种无状态的协议,服务器单从网络连接上是无法知道客户身份的。这时候服务器就需要给客户端颁发一个cookie,用来确认用户的身份。

简单的说,cookie就是客户端保存用户信息的一种机制,用来记录用户的一些信息。

原理:web服务器通过在http响应消息头增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在http请求消息中增加Cookie请求头字段将Cookie回传给web服务器。

cookie的构成

服务器端向客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要向客户端发送的cookie,cookie格式如下:

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2019 11:29:42 GMT;HttpOnly;secure"

其中name=value是必选项,其它都是可选项。Cookie的主要构成如下:

  • name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的。

  • value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码

  • domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:e.baidu.com),也可以不包含它(如:.baidu.com,则对于baidu.com的所有子域都有效)。

  • path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie。

  • expires:失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式。如果客户端和服务器端时间不一致,使用expires就会存在偏差。并且如果给cookie设置一个过去的时间,浏览器会立即删除该cookie

  • max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。

  • HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置。

  • secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。

这里强调一点,是Cookie的不可跨域名性

很多网站都会使用Cookie,不同浏览器采用不同的方式保存Cookie,而且每个网站的Cookie只能够被对应的网站使用。意思就是说当浏览器访问baidu时,只会带baidu的Cookie,而不会带其他网站的Cookie,这就是Cookie的不可跨域名性 。

Cookie在客户端是由浏览器来管理的。浏览器可以保证各个网站只能操作各个网站的Cookie,从而保证用户的隐私安全。

cookie的特点

Cookie并不提供修改、删除操作

如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。

如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。

注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。(这点,验证了,如果path不一致的话,的确删除不了)

补充:

Cookie的不可跨域名性

Cookie的不可跨域名性主要体现在以下几个方面:

  • 隐私安全机制:Cookie的隐私安全机制决定了它通常不允许跨域名访问。这是为了防止恶意网站获取用户在其他网站的信息。因此,由域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。
  • 域名限制:Cookie的domain属性指定了可访问此Cookie的域名。非顶级域名(如二级或三级域名)设置的Cookie的domain只能为顶级域名或者该二级或三级域名本身,不能设置为其他二级域名的Cookie。例如,一个二级域名只能读取设置了domain为顶级域名或者自身的Cookie,不能读取其他二级域名domain的Cookie。
  • 跨域设置的复杂性:虽然可以通过一些设置实现Cookie的跨域访问,但这需要服务端和客户端的配合。服务端需要设置响应头Access-Control-Allow-Credentials: true和Access-Control-Allow-Origin: 请求域名,而客户端在请求中需要设置withCredentials或credentials: include以允许发送Cookie。
  • 同源策略:浏览器默认遵循同源策略,不允许跨域请求携带Cookie。这意味着在发送跨域请求时,浏览器不会发送相应域的Cookie到服务器端。

总结:

  • Cookie的不可跨域名性主要是为了保护用户的隐私安全,防止恶意网站获取用户在其他网站的信息。
  • 通过设置Cookie的domain属性以及服务端和客户端的配合,可以在某些情况下实现Cookie的跨域访问,但这需要谨慎操作,并确保不违反隐私和安全原则。
  • 在设计和开发网站或Web应用时,需要充分考虑Cookie的跨域问题,确保用户的隐私和数据安全。
js对cookie的所有操作总结

在JavaScript中,对cookie的操作主要包括读取、设置、删除和检查是否存在。由于JavaScript本身并没有直接提供完整的cookie操作API,我们通常使用document.cookie属性来与cookie进行交互。以下是对JavaScript中cookie操作的总结:

读取Cookie

JavaScript通过document.cookie属性可以读取当前页面所在域名下的所有cookie,但它返回的是一个字符串,其中包含了所有cookie,它们之间用分号和空格分隔。你需要手动解析这个字符串以获取特定的cookie值。

function getCookie(name) {  
    const value = `; ${document.cookie}`;  
    const parts = value.split(`; ${name}=`);  
    if (parts.length === 2) return parts.pop().split(';').shift();  
}  
  
const cookieValue = getCookie('cookieName');
设置Cookie

设置cookie可以通过直接设置document.cookie属性的值来完成。你需要提供一个符合cookie格式的字符串,其中可能包含cookie的名称、值、过期时间、域名、路径、安全标志和HttpOnly标志等。

function setCookie(name, value, options = {}) {  
    options = {  
        expires: (options.expires instanceof Date) ? options.expires : new Date(Date.now() + options.expires || 3600000), // 默认为1小时  
        path: options.path || '/',  
        domain: options.domain || '',  
        secure: options.secure || false,  
        httpOnly: options.httpOnly || false  
    };  
  
    if (options.httpOnly) {  
        // 注意:JavaScript 无法直接设置 HttpOnly 属性,这需要在服务器端设置  
        // 这里只是模拟一个完整的cookie字符串  
        const cookieString = `${name}=${encodeURIComponent(value)}; expires=${options.expires.toUTCString()}; path=${options.path}; domain=${options.domain}; secure; HttpOnly`;  
        console.log(cookieString); // 输出字符串,但在实际中你需要在服务器端设置这个cookie  
    } else {  
        document.cookie = `${name}=${encodeURIComponent(value)}; expires=${options.expires.toUTCString()}; path=${options.path}; domain=${options.domain}; secure=${options.secure ? 'true' : ''}`;  
    }  
}  
  
setCookie('cookieName', 'cookieValue', { expires: 7 * 24 * 60 * 60 * 1000 }); // 设置7天后过期
删除Cookie

删除cookie实际上是通过设置cookie的过期时间为一个过去的日期来实现的。

function deleteCookie(name) {  
    document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/; domain=${location.hostname};`;  
}  
  
deleteCookie('cookieName');
检查Cookie是否存在
if (getCookie('cookieName')) {  
    // cookie存在  
} else {  
    // cookie不存在  
}
注意事项
  • 由于安全原因,JavaScript无法直接设置HttpOnly属性的cookie。HttpOnly属性用于防止客户端脚本(如JavaScript)访问cookie,这样即使发生了跨站脚本攻击(XSS),攻击者也无法窃取cookie。HttpOnly cookie只能通过HTTP请求发送到服务器。
  • 当涉及到cookie的过期时间时,请注意时区问题。Date.now()返回的是自1970年1月1日00:00:00 UTC(世界标准时间)以来的毫秒数。因此,在设置过期时间时,你需要确保使用UTC时间。
  • 在设置cookie时,请确保cookie的名称和值不包含特殊字符,或者使用encodeURIComponent函数对它们进行编码。

session

什么是session?

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。

客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了

session的工作步骤

因为HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是服务器向用户的浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。这个id可以让Session依据Cookie来识别是否是同一个用户。

简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie,所以说session是基于Cookie的

该Cookie是服务器自动颁发给浏览器的,不用我们手工创建的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中,并且各浏览器窗口间不共享,关闭浏览器就会失效。

工作步骤:

将客户端称为 client,服务端称为 server

  • 产生 sessionID:session 是基于 cookie 的一种方案,所以,首先要产生 cookie。client 第一次访问 server,server 生成一个随机数,命名为 sessionID,并将其放在响应头里,以 cookie 的形式返回给 client,client 以处理其他 cookie 的方式处理这段 cookie。大概是这样:cookie:sessionID=135165432165

  • 保存 sessionID: server 将要保存的数据保存在相对应的 sessionID 之下,再将 sessionID 保存到服务器端的特定的保存 session 的内存中(如 一个叫 session 的哈希表)

  • 使用 session: client 再次访问 server,会带上首次访问时获得的 值为 sessionID 的cookie,server 读取 cookie 中的 sessionID,根据 sessionID 到保存 session 的内存寻找与 sessionID 匹配的数据,若寻找成功就将数据返回给 client。

session的有效期

Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

cookie与session的区别

  • Cookie数据存放在客户端,Session数据放在服务器端

  • Cookie的安全性一般,他人可通过分析存放在本地的Cookie并进行Cookie欺骗。在安全性第一的前提下,选择Session更优。重要交互信息比如权限等就要放在Session中,一般的信息记录放Cookie中

  • 单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,而Session原则上没有限制

  • Session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用Cookie。

  • Session 的运行依赖Session ID,而 Session ID 是存在 Cookie 中的,也就是说,如果浏览器禁用了 Cookie,Session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 Session ID,也就是地址重写)

localStorage

什么是localStorage?

localStorage 是 HTML5 提供的一个 API,他本质上是一个hash(哈希表),是一个存在于浏览器上的 hash(哈希表)。

localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信

localStorage使用方法

localStorage和sessionStorage使用时使用相同的API:

localStorage.setItem("key","value");	//以“key”为名称存储一个值“value”

localStorage.getItem("key");	//获取名称为“key”的值

localStorage.removeItem("key");	//删除名称为“key”的信息。

localStorage.clear();	//清空localStorage中所有信息

localStorage 是一个保存于客户端的哈希表,可以用来保存本地的一些数据。并且不会因为刷新而释放,所以,可以使用 localStorage 来实现变量的持久化存储

localStorage的特点

  • localStorage 与 HTTP 没有任何关系,所以在HTTP请求时不会带上 localStorage 的值

  • 只有相同域名的页面才能互相读取 localStorage,同源策略与 cookie 一致

  • 不同的浏览器,对每个域名 localStorage 的最大存储量的规定不一样,超出存储量会被拒绝。最大存5M 超过5M的数据就会丢失。而 Chrome 10MB 左右

  • 常用来记录一些不敏感的信息

  • localStorage 理论上永久有效,除非用户清理缓存

localStorage MDN

只读的localStorage 属性允许你访问一个Document 源(origin)的对象Storage;存储的数据将保存在浏览器会话中。

localStorage 类似 sessionStorage,但其区别在于:

  • 存储在 localStorage 的数据可以长期保留
  • 当页面会话结束——也就是说,当页面被关闭时,存储在 sessionStorage 的数据会被清除

应注意,无论数据存储在 localStorage 还是 sessionStorage ,它们都特定于页面的协议。

测试
  • 打开一个页面,打开console控制台,
    • 输入localStorage.setItem(‘z’,‘j’),在当前窗口的当前页面,能够通过localStorage.getItem(‘z’)拿到值 j 的。
    • 强制刷新页面,也能通过localStorage.getItem(‘z’)拿到值 j 的。
    • 在当前窗口输入百度的网址,等页面加载完成后,此时访问localStorage.getItem(‘z’),访问不到。再输入原地址,等待加载完成,再通过localStorage.getItem(‘z’)仍然能够拿到值j。
    • 打开一个新的窗口,输入原地址,仍然可以通过localStorage.getItem(‘z’)拿到值 j
    • 关闭浏览器,再次输入原地址,仍然可以通过localStorage.getItem(‘z’)拿到值 j
  • 测试同一ip,但是不同端口,是否能访问到
    • 访问http://localhost:9091/,打开控制台 ,使用localStorage.setItem(‘kk’,‘jj’);再打开另一个窗口,访问http://localhost:8085/,使用localStorage.getItem(‘kk’),发现返回的是null,说明同一ip,不同端口,其localStorage值不能共享。
    • 但是此时如果,我访问http://localhost:9091/a/b,此时,再使用localStorage.getItem(‘kk’),能够访问得到jj,说明同ip,同端口,不同路径是可以共享 的。

得到的结论:如果不手动清理掉localStorage中的数据,那么通过localStorage存储的数据,将会一直存在。

sessionStorage

  • sessionStorage 的所有性质基本上与 localStorage 一致,唯一的不同区别在于:
  • sessionStorage 的有效期是页面会话持续,如果页面会话(session)结束(关闭窗口或标签页),sessionStorage 就会消失。而 localStorage 则会一直存在。
  • 感觉还是还是没说清楚,下面看看mdn的解释

sessionStorage MDN

sessionStorage 属性允许你访问一个,对应当前源的 session Storage 对象。它与 localStorage 相似,不同之处在于 localStorage 里面存储的数据没有过期时间设置,而存储在 sessionStorage 里面的数据在页面会话结束时会被清除

  • 页面会话在浏览器打开期间一直保持,并且重新加载! 或 恢复页面! 仍会保持原来的页面会话

  • 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,这点和 session cookie 的运行方式不同。

  • 打开多个相同的 URL 的 Tabs 页面,会创建各自的 sessionStorage

  • 关闭对应浏览器标签或窗口,会清除对应的 sessionStorage。

测试
  1. 一个浏览器打开2个窗口,这2个窗口,是同一个地址的2个页面(A页面和B页面),在A页面中设置sessionStorage.setItem(‘KA’,‘KB’),在A窗口不关闭的情况下,它是能够通过sessionStorage.getItem(‘KA’)得到KB的,但是在B窗口通过sessionStorage.getItem(‘KA’)得到的是null。

  2. 打开一个地址的页面,然后使用sessionStorage.setItem(‘A’,‘B’)。然后,再ctrl + F5强制刷新页面,发现,当前页面仍然能够使用sessionStorage.getItem(‘A’)获取到B

    • 与vuex的区别,vuex的数据保存在运行内存当中,当刷新页面时,vuex的数据会丢失掉
  3. 打开一个地址的页面,然后等页面加载完成后,使用sessionStorage.setItem(‘A’,‘B’),然后在当前窗口的地址栏输入百度的网址,再打开console控制台,此时访问sessionStorage.getItem(‘A’),返回的是null。此时,在原窗口,输入原地址,在控制台继续访问sessionStorage.getItem(‘A’),发现此时能够继续访问的到B

  4. 测试同一ip,但是不同端口,是否能访问到

    • 访问http://localhost:9091/,打开控制台 ,使用sessionStorage.setItem(‘kk’,‘jj’);在该窗口地址栏,访问http://localhost:8085/,使用sessionStorage.getItem(‘kk’),发现返回的是null,说明同一ip,不同端口,其sessionStorage值不能共享。
    • 但是此时如果,我在该窗口地址栏,输入http://localhost:9091/a/b,此时,再使用sessionStorage.getItem(‘kk’),能够访问得到jj,说明同ip,同端口,不同路径是可以共享 的。

得到的结论:只要当前的页面不关闭,不管里面怎么跳地址(刷新或地址跳来跳去),都能通过sessionStorage访问到当前源设置的数据。

localStorage与sessionStorage的区别

  • localStorage生命周期是永久的,除非被清除,否则永久保存,而sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除

  • 相同点可以参考localStorage的特点。这里再强调一下,这两个存储方式用来存放数据大小一般为5MB,并且仅在客户端(即浏览器)中保存,不参与和服务器的通信。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐