0%

cookie和session

2017年9月11日 上午9:23

概述

  1. 我结合我昨天看的一个电影加勒比海盗5-死无对证来说明我对cookie和session的理解吧。
  2. 电影中的小男主角在自己还是一个小屁孩的时候,去荷兰号去找父亲,父亲当时将自己脖子中的项链给了小男主角,就是希望有一天等小男主角长大之后还可以相认。果然,那主角不负众找到了三叉戟,破除了海洋中的所有诅咒。最后,小男主角和父亲相见的时候,父亲第一眼看的是哪个项链,然后确认了之后他们拥抱在一起(ps:关键是小男主角还找了一个漂亮的媳妇,bravo!)
  3. 先说cookie
  4. 这里的项链就是我们这里的一个cookie,cookie由服务器产生,cookie在给了客户端之后服务器就没有了(给了儿子,父亲自然就没了),由于http是无状态的,所以一旦下一次访问(男主就和父亲很难相见),服务器是不认识谁了,但是客户端有了这个cookie,服务器就根据这个cookie知道你是你是谁了,这两个人就相认了。
  5. 这里有几个特殊情况,例如这个cookie让别人拿走,用在了其他的浏览器上,那么服务器也是不知道了(这样父亲就认错孩子了),但是利用这种情况,可以做多个客户端浏览器的同步。还有就是一个服务器可以为很多不同的用户服务(父亲有好多的孩子,都给了他们不同的项链),服务器在把自己的cookie给出去之后,其实对于自己产生的cookie的具体内容也不知道了,他得根据客户端给他啥,他就知道啥,认为这就是自己给客户端的,简单的说:给啥我要啥(这一点的判断是浏览器根据访问的url来划分的,浏览器访问不同的url,会把不同的url对应的cookie全都传过去),这也就解决了一个服务器多个客户端的问题,客户端给我啥我要啥,这时候可以理解成的情景是:就是两个人在普通的交流,这个交流就一个回合,但是客户端这人用本子记录内容,但是服务器这个人比较懒
  6. 对于服务器来说,只要有人访问他,他就给他一个cookie,其中就是一个Jsessionid。对于双11来说,你想想他会产生多少个Jsessonid,服务器这么做的原因是想和各种来找他的人都建立起关系,维护住关系。
  7. cookie中还有一个domain的概念,我理解就是兄弟姐妹之间公用一个cookie作为信物,而不是每个人一个。
  8. 还要就是session
  9. Session是保存在服务端,这个可以理解成父亲在根据cookie认出自己的儿子之后,从自己的记忆中找到了很多自己和儿子相处的儿时时光,这只有父亲一个知道,其他人根本不知道,是私有的。这里的私有记忆就是session,只能让服务器自己程序执行的时候使用,作为自己一些功能实现的判断依据,用来写代码逻辑用的
  10. 这里还说明了其实session和cookie其实是完全不同的东西。他们之间的联系是当一个 Session 开始时,Servlet 容器将创建一个 HttpSession 对象,Servlet 容器为 HttpSession 分配一个唯一标识符,称为 Session ID这个sessionid是一个cookie,是为了让服务端能够区分开不同的用户,那么根据这个cookie就可以在服务端的代码逻辑中过滤一些人(eg:防止用户没登录就访问购物车界面,然后告知他没登录)。这一点也可以从javaEE手册中证明,session和cookie是没有继承和实现关系的。
  11. 其他:
    1. session服务器内存中 cookie客户端硬盘中
    2. Session的有效时间通过xml控制,而cookie直接通过代码控制
      1. Tomcat自带一个web.xml文件,如我们在使用session中没有在自己的项目web.xml中声明有效时间,那么默认使用就是tomcat中web.xml文件的
    3. 在禁止使用cookie的地方使用session
      1. response.encodeURL的用法 - zhaogengzi的专栏 - CSDN博客
      2. response.encodeURL的用法 - langqiao123的专栏 - CSDN博客


可以从http报文头中去观察cookie的过程

详细的知识点

直接看这个txt文档排版比较整齐,下面那个是为了方便粘贴复制
cookie和session.txt

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
================================
================================
================================

会话跟踪

1. 什么是会话
* 用户拨打10086,从服务台接通后会话开始;
* 用户发出话费查询请求,服务台响应。这是该会话中的一个请求;
* 用户发出套餐变更请求,服务台响应。这是该会话中的又一个请求;
* ...
* 用户挂断电话,会话结束。

2. 会话的特性
* 一个会话中可能包含多个请求;
* 一个会话中发出请求的用户是唯一的;

3. JavaWeb会话
* 从用户打开本站第一个页面开始,会话也开始了;
* 用户会发出0~n个请求;
* 用户关闭浏览器会话结束了。

4. 什么是会话跟踪技术
HTTP是无状态协议,也就是没有记忆力的协议,每个请求之间无法共享数据。
这就无法知道会话什么时候开始,什么时候结束,也无法确定发出请求的用户身份。这说明需要使用额外的手段来跟踪会话!
* 在一个会话中共享数据即会话跟踪技术

------------------------------------

Cookie

1. 什么是Cookie

* Cookie是HTTP协议的规范之一,它是服务器和客户端之间传输的小数据。
* 首先由服务器通过响应头把Cookie传输给客户端,客户端会将Cookie保存起来。
* 当客户端再次请求同一服务器时,客户端会在请求头中添加该服务器保存的Cookie,发送给服务器。
* Cookie就是服务器保存在客户端的数据!
* Cookie就是一个键值对!!!

2. Cookie规范
* Cookie通过请求头和响应头在服务器与客户端之间传输;
* Cookie大小限制在4KB之内;
* 一台服务器在一个客户端最多保存20个Cookie;
* 一个浏览器最多可以保存300个Cookie;

虽然Cookie规范是如此,但在今天,浏览器厂商的竞争异常激烈,所以多少会超出Cookie规则的限制。但也不会超出过多!

3. Cookie与请求头和响应头

* 服务器向客户端发送Cookie的响应头为Set-Cookie,例如:Set-Cookie:cookiename=cookievalue
* 客户端向服务器发送Cookie的请求头为Cookie,例如:Cookie:cookiename=cookievalue

4. Servlet中向客户端发送Cookie
Cookie cookie1 = new Cookie("test1", "abcdefg");
Cookie cookie2 = new Cookie("test2", "ABCDEFG");
response.addCookie(cookie1);
response.addCookie(cookie2);

5. Servlet中获取客户端发送过来的Cookie

Cookie[] cs = request.getCookies();
if(cs != null) {
for(Cookie c : cs) {
System.out.println(c.getName() + "=" + c.getValue());
}
}

=============================

Cookie的细节

1. Cookie的maxAge
当服务器创建Cookie对象后,可以调用setMaxAge()方法设置Cookie的最大生命。
* maxAge > 0:表示Cookie在客户端硬盘上保存的最大时间,单位为秒;
* maxAge < 0:表示Cookie不会被浏览器保存到硬盘上,而只在浏览器内存中存活,一旦客户端关闭浏览器在,那么Cookie就消失;
* maxAge == 0:表示删除Cookie,例如客户端硬盘已经存在名为abc的Cookie,如果服务器再向客户端发送名为abc,并且maxAge为0的Cookie,那么表示删除客户端上的名为abc的Cookie。

2. Cookie的path
浏览器在访问BServlet时,是否要带上AServlet保存的Cookie呢?这要看Cookie的path了。
现有资源如下:
* http://localhost:8080/day06_2/servlet/AServlet
* http://localhost:8080/day06_2/servlet/BServlet,保存名为xxx的Cookie
* http://loclahost:8080/day06_2/servlet/CServlet,保存名为yyy的Cookie
* http://loclahost:8080/day06_2/servlet/user/DServlet, 保存名为zzz的Cookie

// 没有设置Cookie的path
AServlet {
Cookie c = new Cookie("xxx", "XXX");
response.addCookie(c);
}
// 设置了Cookie的path为/day06_2
CServlet {
Cookie c = new Cookie("yyy", "YYY");
c.setPath="/day06_2";
response.addCookie(c);
}
DServlet {
Cookie c = new Cookie("zzz", "ZZZ");
resposne.addCookie(c);
}


在BServlet中保存的Cookie没有设置path,那么它的path默认为当前BServlet的所在路径,即“/day06_2/servlet”。
在CServlet中保存的Cookie设置了path为/day06_2。
在DServlet中保存的Cookie没有设置path,那么它的path默认为DServlet的所在路径,即“day06_2/servlet/user”


当访问AServlet时,是否要带上xxx这个Cookie呢?因为AServlet的访问路径为/day06_2/servlet/BServlet,它包含了xxx的path,即/day06_2/servlet,所以需要带上。

当访问AServlet时,是否要带上yyy这个Cookie呢?因为AServlet的访问路径为/day06_2/servlet/BServlet,它包含了xxx的path,即/day06_2,所以需要带上。

当访问AServlet时,是否要带上zzz这个Cookie呢?因为AServlet的访问路径为/day06_2/servlet/BServlet,它不包含zzz的path,即/day06_2/servlet/user,所以不会带上。


3. Cookie的domain
Cookie的path是在同一主机中指定共享Cookie,如果主机不同那么就一定不能共享Cookie,无论path是什么。
如果希望不同的二级域名中可以共享Cookie,那么就要设置Cookie的domain了。
例如:news.baidu.com、tieba.baidu.com、zhidao.baidu.com,它们的域名不同,但百度希望它们之间可以共享Cookie,那么就要设置domain了。

1). 设置Cookie的path为“/”,例如:cookie.setPath("/");
2). 设置Cookie的domain,例如:cookie.setDomain(".baidu.com"),其中domain中没有指定域名前缀!

在news.baidu.com主机中的某个项目中保存了Cookie
在tieba.baidu.com主机中某个项目中获取Cookie

当然这需要配置两个虚拟主机才行。


4. Cookie保存中文
Cookie的name和value都是不能保存中文的,但可以先把中文转换成URL编码,然后在保存到Cookie的name和value中。
String name = "姓名";
String value = "张三";
name = URLEncoder.encode(name, "utf-8");
value = URLEncoder.encode(value, "utf-8");

Cookie c = new Cookie(name, value);
response.addCookie(c);

在获取Cookie时,再使用URL解码即可。
Cookie[] cs = request.getCookies();
if(cs != null) {
for(Cookie c : cs) {

byte[] b=c.getName().getBytes(iso-8859-1);
String name = new String(b,"utf-8");
String name = URLDecoder.decode(c.getName(), "utf-8");
String value = URLDecoder.decode(c.getValue(), "utf-8");
System.out.println(name + "=" + value);
}
}

=============================
=============================
=============================

HttpSession

在JavaWeb中提供了HttpSession类,用来表示http会话。

1. 获取HttpSession
HttpSession session = request.getSession();
HttpSession session = request.getSession(false);

2. 域功能
session是域对象,所以有setAttribute()和getAttribute()等方法
服务器会为每个会话创建一个session对象,所以session中的数据可供当前会话中所有servlet共享。

3. 登录案例
请求功能:
1. 如果登录功能,在session中保存user对象
2. 访问index1.jsp,查看session中是否存在user对象,如果存在,说明已经登录过。
3. 访问index2.jsp,查看session中是否存在user对象,如果存在,说明已经登录过。
如果关闭了浏览器,那么会话结束,再打开浏览器就开始了一个新会话,那么直接访问index1.jsp或index2.jsp时,session是新的,没有保存user对象,那么表示还没有登录。

4. session的原理
session是依赖Cookie实现的。
session是服务器端对象
当用户第一次使用session时(表示第一次请求服务器),服务器会创建session,并创建一个Cookie,在Cookie中保存了session的id,发送给客户端。这样客户端就有了自己session的id了。但这个Cookie只在浏览器内存中存在,也就是说,在关闭浏览器窗口后,Cookie就会丢失,也就丢失了sessionId。
当用户第二次访问服务器时,会在请求中把保存了sessionId的Cookie发送给服务器,服务器通过sessionId查找session对象,然后给使用。也就是说,只要浏览器容器不关闭,无论访问服务器多少次,使用的都是同一个session对象。这样也就可以让多个请求共享同一个session了。
当用户关闭了浏览器窗口后,再打开浏览器访问服务器,这时请求中没有了sessionId,那么服务器会创建一个session,再把sessionId通过Cookie保存到浏览器中,也是一个新的会话开始了。原来的session会因为长时间无法访问而失效。
当用户打开某个服务器页面长时间没动作时,这样session会超时失效,当用户再有活动时,服务器通过用户提供的sessionId已经找不到session对象了,那么服务器还是会创建一个新的session对象,再把新的sessionId保存到客户端。这也是一个新的会话开始了。

  设置session超时时间
web.xml文件中配置如下:
<session-config>
<session-timeout>30</session-timeout>
</session-config>


5. session与浏览器
session对象是保存在服务器端的,而sessionId是通过Cookie保存在客户端的。
因为Cookie不能在多个浏览器中共享,所以session也不能在多个浏览器中共享。也就是说,使用IE登录后,再使用FireFox访问服务器还是没有登录的状态。

而且同时打开多个相同浏览器的窗口,是在使用同一session。如果你使用的是老浏览器,例如IE6,那么就会每个窗口一个session。

6. session的API
* String getId():获取sessionId;
* int getMaxInactiveInterval():获取session可以的最大不活动时间(秒),默认为30分钟。当session在30分钟内没有使用,那么Tomcat会在session池中移除这个session;
* void setMaxInactiveInterval(int interval):设置session允许的最大不活动时间(秒),如果设置为1秒,那么只要session在1秒内不被使用,那么session就会被移除;
* long getCreationTime():返回session的创建时间,返回值为当前时间的毫秒值;
* long getLastAccessedTime():返回session的最后活动时间,返回值为当前时间的毫秒值;
* void invalidate():让session失效!调用这个方法会被session失效,当session失效后,客户端再次请求,服务器会给客户端创建一个新的session,并在响应中给客户端新session的sessionId;
* boolean isNew():查看session是否为新。当客户端第一次请求时,服务器为客户端创建session,但这时服务器还没有响应客户端,也就是还没有把sessionId响应给客户端时,这时session的状态为新。

7. URL重写
session依赖Cookie,这是因为服务器需要把sessionId保存到客户端。如果用户的浏览器关闭了Cookie功能,那么session不能使用了!
还可以在浏览器关闭了Cookie后使用URL重写的方法保存sessionId,这需要在每个URL后面都加上sessionId!这样用户的请求中就包含了sessionId,服务器就可以通过sessionId找到对应的session对象了。
使用response.encodeURL()方法对URL进行编码,这样URL中会智能的添加sessionId。
 当浏览器支持cookie时,response.encodeURL()方法不会在URL后追加sessionId
当浏览器不支持cookie时,response.encodeURL()方法会在URL后追加sessionId