cookie与session

常用的会话跟踪技术Cookie与Session。

会话跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。

Cookie通过客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

一.cookie

Cookie实际上是一小段的文本信息。

客户端向服务器发起请求,若服务器需要记录该用户状态Cookie的处理:

  • 服务器使用response向客户端发送cookie
  • 浏览器将cookie保存
  • 之后每次http请求浏览器都会将cookie发送给服务器端。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容

服务器端的发送与解析

发送cookie

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

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"
其中name=value是必选项,其它都是可选项。

Cookie的主要构成如下:

name:唯一确定的cookie名称。不区分大小写。  Name 和 Value 属性由程序设定,默认值都是空引用。

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

domain(域):cookie对哪个域有效Domain属性的默认值为当前URL的域名部分。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:

yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效).

http://www.baidu.com/xxx/login.aspx 页面中发出一个cookie,Domain属性缺省就是www.baidu.com ,
可以由程序设置此属性为需要的值。  

若值是域名,比如www.china.com。这是对path路径属性的一个延伸。
如果我们想让 www.china.com能够访问bbs.china.com设置的cookies,该怎么办? 
把domain属性设置成“china.com”, 并把path属性设置成“/”。

path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,向指定域中匹配的路径发送cookiePath属性的默认值是根目录,即 ”/”

如果http://www.china.com/test/index.html 建立了一个cookie,那么在http://www.china.com/test/目录里的所有页面,
以及该目录下面任何子目录里的页面都可以访问这个cookie.

如果http://www.china.com/test/ 需要访问http://www.china.com/test/index.html设置的cookes,该怎么办?
把cookies的path属性设置成“/”。在指定路径的时候,凡是来自同一服务器,URL里有相同路径
的所有WEB页面都可以共享cookies。

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

max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒)。max-age的优先级高于expires

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

secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了服务器端设置

cookie示例如下:

1.直接设置cookie

1

2

3

4

5

6

7

8

9

var http = require('http');

var fs = require('fs');

http.createServer(function(req, res) {

  res.setHeader('status', '200 OK');

  res.setHeader('Set-Cookie', 'isVisit=true;domain=.yourdomain.com;path=/;max-age=1000');

  res.write('Hello World');

  res.end();

}).listen(8888);

console.log('running localhost:8888')

2.封装对cookie的设置(直接设置Set-Cookie过于原始,可以对cookie的设置过程做如下封装)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

var serilize = function(name, val, options) {

  if (!name) {

    throw new Error("coolie must have name");

  }

  var enc = encodeURIComponent;   //编码

  var parts = [];

   

  val = (val !== null && val !== undefined) ? val.toString() : "";

  options = options || {};

  parts.push(enc(name) + "=" + enc(val));    //name=value  (name和value是URI编码过的)

  // domain中必须包含两个点号

  if (options.domain) {

    parts.push("domain=" + options.domain);

  }

  if (options.path) {

    parts.push("path=" + options.path);

  }

  // 如果不设置expires和max-age浏览器会在页面关闭时清空cookie

  if (options.expires) {

    parts.push("expires=" + options.expires.toGMTString());

  }

  if (options.maxAge && typeof options.maxAge === "number") {

    parts.push("max-age=" + options.maxAge);

  }

  if (options.httpOnly) {

    parts.push("HTTPOnly");

  }

  if (options.secure) {

    parts.push("secure");

  }

   

  return parts.join(";");

}

 

注意:

如果给cookie设置一个过去的时间,浏览器会立即删除该cookie;

domain项必须有两个点(.),因此localhost是无效的,浏览器将拒绝设置cookie!

服务器端解析cookie

cookie可以设置不同的域与路径,同一个name value可用于不同域不同路径下,浏览器会按照与当前请求url或页面地址最佳匹配的顺序来排定先后顺序

所以当前端传递到服务器端的cookie有多个重复name value时,我们只需要最匹配的那个,也就是第一个。

服务器端解析代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

var parse = function(cstr) {

  if (!cstr) {

    return null;

  }

   

  var dec = decodeURIComponent;

  var cookies = {};

  var parts = cstr.split(/\s*;\s*/g);

  parts.forEach(function(p){

    var pos = p.indexOf('=');

    // name 与value存入cookie之前,必须经过编码

    var name = pos > -1 ? dec(p.substr(0, pos)) : p;

    var val = pos > -1 ? dec(p.substr(pos + 1)) : null;

    //只需要拿到最匹配的那个

    if (!cookies.hasOwnProperty(name)) {

      cookies[name] = val;

    }/* else if (!cookies[name] instanceof Array) {

      cookies[name] = [cookies[name]].push(val);

    } else {

      cookies[name].push(val);

    }*/

  });

   

  return cookies;

}

客户端的存取

浏览器将后台传递过来的cookie进行管理,并且允许开发者在JavaScript中使用document.cookie来存取cookie

当用来时,返回当前页面可用的(根据,字符串的格式如下:

document.cookie   获取cookie的域、路径、失效时间和安全设置(字符串)

1

"name1=value1;name2=value2;name3=value3";

document.cookie="       "     设置一个新的cookie字符串。    这个字符串会被解释并添加到现有的cookie集合中

1

document.cookie = "_fa=aaaffffasdsf;domain=.dojotoolkit.org;path=/"

设置document.cookie并不会覆盖cookie,除非设置的name value domain path都与一个已存在cookie重复

针对cookie的添加、修改、删除。封装函数来处理cookie

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

var cookieUtils = {

    get: function(name){

     var cookieName=encodeURIComponent(name) + "=";

     //只取得最匹配的name,value

     var cookieStart = document.cookie.indexOf(cookieName);

     var cookieValue = null;

      

     if (cookieStart > -1) {

      // 从cookieStart算起

      var cookieEnd = document.cookie.indexOf(';', cookieStart);

      //从=后面开始

      if (cookieEnd > -1) {

       cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));

      } else {

       cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, document.cookie.length));

      }

     }

      

     return cookieValue;

    },

     

    set: function(name, val, options) {

      if (!name) {

        throw new Error("coolie must have name");

      }

      var enc = encodeURIComponent;

      var parts = [];

       

      val = (val !== null && val !== undefined) ? val.toString() : "";

      options = options || {};

      parts.push(enc(name) + "=" + enc(val));

      // domain中必须包含两个点号

      if (options.domain) {

        parts.push("domain=" + options.domain);

      }

      if (options.path) {

        parts.push("path=" + options.path);

      }

      // 如果不设置expires和max-age浏览器会在页面关闭时清空cookie

      if (options.expires) {

        parts.push("expires=" + options.expires.toGMTString());

      }

      if (options.maxAge && typeof options.maxAge === "number") {

        parts.push("max-age=" + options.maxAge);

      }

      if (options.httpOnly) {

        parts.push("HTTPOnly");

      }

      if (options.secure) {

        parts.push("secure");

      }

       

      document.cookie = parts.join(";");

    },

    delete: function(name, options) {

     options.expires = new Date(0);// 设置为过去日期

     this.set(name, null, options);

    }

   }

会话Cookie和持久Cookie

会话cookie:若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。。会话cookie一般不存储在硬盘上而是保存在内存里。

持久Cookie:若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在浏览器的不同进程间共享。

Cookie具有不可跨域名性        也就是说:浏览器访问百度不会带上谷歌的cookie。

 

二. Session

  Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

 每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?

用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。

 1、两个问题:

1)什么东西可以让你每次请求都把SessionId自动带到服务器呢?

显然就是cookie了,如果你想为用户建立一次会话,可以在用户授权成功时给他一个唯一的cookie。当一个用户提交了表单时,浏览器会将用户的SessionId自动附加在HTTP头中(这是浏览器的自动功能),当服务器处理完这个表单后,将结果返回给SessionId所对应的用户。

2)储存需要的信息。服务器通过SessionId作为key,读写到对应的value,这就达到了保持会话信息的目的。

  2、session的创建:

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了sessionId,如果已包含则说明以前已经为此客户端创建过session,服务器就按照sessionId把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含sessionId,则为此客户端创建一个session并且生成一个与此session相关联的sessionId,sessionId的值是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionId将被在本次响应中返回给客户端保存。

  3、禁用cookie:

  如果客户端禁用了cookie,通常有两种方法不依赖cookie实现session

1)URL重写,就是把sessionId直接附加在URL路径的后面

2)表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如: 

<form name="testform" action="/xxx"> 
<input type="hidden" name="sessionid"  value="hhjjuubzWoWiBYEnLerjQ99zWpBng!-145788764"> 
<input type="text"> 
</form> 

  4、Session共享:

对于多网站(同一父域不同子域)单服务器,我们需要解决的就是来自不同网站之间SessionId的共享。

由于域名不同(aaa.test.com和bbb.test.com),而SessionId又分别储存在各自的cookie中,因此服务器会认为对于两个子站的访问,是来自不同的会话。

解决的方法:修改cookies的域名为父域名达到cookie共享的目的,从而实现SessionId的共享。带来的弊端就是,子站间的cookie信息也同时被共享了。  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值