JavaScript Cookie
什么是 Cookie?
Cookie 是一些数据, 存储于你电脑上的文本文件中。
当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。
Cookie 的作用就是用于解决 "如何记录客户端的用户信息":
当用户访问 web 页面时,他的名字可以记录在 cookie 中。
在用户下一次访问该页面时,可以在 cookie 中读取用户访问记录。
Cookie 以名/值对形式存储,如下所示:
username=John Doe
当浏览器从服务器上请求 web 页面时, 属于该页面的 cookie 会被添加到该请求中。服务端通过这种方式来获取用户的信息。
设置cookie
使用HTTP头中的Set-Cookie属性设置cookie,然后在服务端响应中发送。这个头会让浏览器保存cookie,然后在后续的请求中重新发送给服务端(如果浏览器不支持cookie或者禁用了cookie,会忽略这个头的)。
下面的例子,浏览器发送第一个请求,请求www.example.org站点的首页:
GET /index.html HTTP/1.1
Host: www.example.org
服务端以两个Set-Cookie头响应:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
服务端的HTTP响应中包含站点的首页。但是它仍会让浏览器设置两个cookie。第一个,"theme",被当做是一个session cookie,因为它没有Expires或者Max-Age属性。当浏览器关闭的时候,浏览器会删掉Session cookie。第二个,”sessionToken",被当成是一个持久性cookie,因为它包含一个Expires属性,这个属性会让浏览器在指定时间内删除cookie。
接下来浏览器发送另一个请求访问spec.html页面。这个请求包含一个CookieHTTP头,里面有服务端设置的两个cookie:
GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123
通过这种方式服务端知道这个请求和上个页面有关。服务端会返回请求页面,可能会在响应中包含更多的Set-Cookie头为了增加新的cookie,修改已存在的cookie或者删除cookie。
服务端可以通过在请求的响应中包含Set-Cookie头的方式修改cookie的值。浏览器就会用新的cookie替换掉旧的值。
cookie的值可以是任意的可打印ASCII字符,但是不包括,,;以及空白字符。cookie的名称也不包括这些字符,还有=,因为=是用来分隔名称和值的。cookie的RFC 2965标准更严格,没有被浏览器全部实现。
cookie也可以通过脚本语音在浏览器端设置。在js中,document.cookie对象就是用来干这个事情的。例如,document.cookie="temperature=20"将会创建一个名称为"temperature"值为"20"的cookie。
Cookie属性
除了名称和值之外,cookie也可以有其他更多的属性。浏览器发送到服务端的cookie不包含属性,只有键值对。cookie的属性被浏览器用来决定何时删除cookie,阻塞cookie或者是否发送cookie到服务端。
Domain和Path
Domain和Path属性定义了cookie的范围。本质上是告诉浏览器cookie属于哪个站点。为了明显的安全原因,cookie只能在当前资源的顶级域名或者子级域名上设置,不能再其他域名和对应的子级域名上设置。例如,example.org站点不能设置一个domain是foo.com的cookie,因为不会允许example.org站点去控制foo.com的cookie。
如果cookie的Domain和Path属性没有被服务端指定,它们默认是当前请求资源的domain以及path。然而,在大多数浏览器中,foo.com中的cookie没有设置domain和设置了domain属性是有区别的。在前一种情况下,cookie只会被发送foo.com的请求。在后一种情况下,所有的子域都会包含这个cookie(例如,docs.foo.com),IE中这条规则是例外的,在IE中这两种情况cookie都会被发送给所有的子域。
下面就是一个用户登录之后站点发送的响应中包含Set-Cookie的例子。HTTP请求是发送到docs.foo.com子域的:
HTTP/1.0 200 OK
Set-Cookie: LSID=DQAAAK…Eaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
Set-Cookie: HSID=AYQEVn…DKrdst; Domain=.foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly
Set-Cookie: SSID=Ap4P…GTEq; Domain=foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
第一个cookie,LSID没有Domain属性,有一个Path属性被设置成了/accounts。这告诉浏览器只有当请求页面包含在docs.foo.com/accounts下时才返回这个cookie。另外两个cookie,HSID和SSID,在浏览器请求任何.foo.com的子域的任何路径时都不会返回。签名的点在最新的标准是可选的。
设置 cookie 值的函数
首先,我们创建一个函数用于存储访问者的名字:
function setCookie(cname,cvalue,exdays)
{
var d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires = "expires="+d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires;
}
函数解析:
以上的函数参数中,cookie 的名称为 cname,cookie 的值为 cvalue,并设置了 cookie 的过期时间 expires。
该函数设置了 cookie 名、cookie 值、cookie过期时间。
获取 cookie 值的函数
然后,我们创建一个函数用于返回指定 cookie 的值:
function getCookie(cname)
{
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
函数解析:
cookie 名的参数为 cname。
创建一个文本变量用于检索指定 cookie :cname + "="。
使用分号来分割 document.cookie 字符串,并将分割后的字符串数组赋值给 ca (ca = document.cookie.split(';'))。
循环 ca 数组 (i=0;i<ca.length;i++),然后读取数组中的每个值,并去除前后空格 (c=ca[i].trim())。
如果找到 cookie(c.indexOf(name) == 0),返回 cookie 的值 (c.substring(name.length,c.length)。
如果没有找到 cookie, 返回 ""。
检测 cookie 值的函数
最后,我们可以创建一个检测 cookie 是否创建的函数。
如果设置了 cookie,将显示一个问候信息。
如果没有设置 cookie,将会显示一个弹窗用于询问访问者的名字,并调用 setCookie 函数将访问者的名字存储 365 天:
function checkCookie()
{
var username=getCookie("username");
if (username!="")
{
alert("Welcome again " + username);
}
else
{
username = prompt("Please enter your name:","");
if (username!="" && username!=null)
{
setCookie("username",username,365);
}
}
}