让服务器有记忆能力之Cookie、Session
会话技术
会话技术指浏览器访问一个网站后,不管点击了多少超链接,发送了多少请求,
一直到关闭浏览器,离开这个服务器的过程称之为一次会话。
为什么要使用会话技术?
比如当我点击淘宝的登录页面,输入用户名密码后,勾选下次自动登录,下次再次访问淘宝时浏览器就会自动帮我登录。
或者是能够保存我上次浏览过的商品信息,猜我喜欢的商品。
以上的操作必须要让服务器知道“”我“”是谁,而http协议恰巧又是无状态协议。
而无状态的协议是什么意思呢? HTTP无状态协议,是指协议对于交互性场景没有记忆能力。
举个例子:
比方说在购物网站上买一个书包:流程如下
1、输入用户名,密码登录
2、选择一款你喜欢的书包,加入购物车
3、购买支付
所谓的登录,只是验证一下你是否是一个合法的用户,合法则跳到指定页面,不合法则提示用户名或密码错误,而当我门完成登录操作以后服务器就忘记了,忘记了你这个人到底有没有认证过。所以在添加商品的时候, 还是需要让你输入用户名密码,验证你的身份。
所以,当页面之间涉及到交互问题的时候,就会很麻烦了,因为这三步是有依赖的,当你输入完用户名密码,点击登录,验证通过服务器会给你返回200/ok,这时候一个请求与相应就结束了,当你选好物品后试图添加到购物车中,添加购物车这个操作和第一步是有关联的,是谁把什么加入了购物车? 这个人有没有在网站上注册过,是不是一个合法的用户呢?所以此时还需要输入用户名和密码,每做一次操作购物车操作时,都需要输入用户名和密码,反反复复输入一遍又一遍,这是因为服务器不知道你20秒前是否已经登录过。
上面的无状态即无登录状态,即服务器不知道某个用户已经登录过一次了,所以每次交互的时候都需要,反复输入用户名和密码,明明只需要在登录的时候输入用户名和密码,然后在数据库中对比用户名密码和和客户端输入的是否一致,但这下在添加购物车操作的时候也需要做同样的操作。即降低了响应速度,又对用户不友好。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另外人们常说的“会话”概念则是上面的交互行为的另一种表述方式。
由于HTTP是一种无状态协议,服务器是服务器知道客户端的状态的,而交互又是需要承前启后的,
即使是简单的购物车功能也要知道用户之选择了什么商品,于是就诞生了两种会话技术、Cookie、Session。
Cookie
HTTP是无状态协议,所有服务器从网络连接上无法得知用户的状态,那么怎么办呢? 就给客户端颁发一个通行证吧,用户的状态都保存在这个通行证上面,无论谁访问的时候都需要携带这个通行证,这样服务器就能从通行证上得知用户的身份了,而这个通行证就是Cookie。
Cookie的工作原理:
如果服务器需要记录该用户的状态。就使用response像客户端发送一个Cookie ,客户端浏览器就会把Cookie保存起来,当浏览器再次向服务器发送请求的时候就会携带该Cookie和URL一起提交到服务器,服务器检查该Cookie从而得知用户的状态,服务器还可以根据用户的状态修改Cookie的内容。
Cookie类用于创建一个Cookie对象
response接口中定义了一个addCookie方法,它用于在其响应头中增加一个响应的Set-Cookie头字段
request接口中定义了一个getCookie方法,它用于获取客户端提交的Cookie
常用的Cookie方法
Cookie API |
---|
public Cookie(String name,String value) |
setValue 与 getValue |
setPath 与 getPath |
setDomain 与 getDomain |
getName |
cookie.setMaxAge(int expiry); 设置Cookie的有效期 |
简单使用Cookie
使用Cookie记录用户上次访问时间
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/text;charset=utf-8");
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie.getName().equals("lastLoginTime")) {
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
resp.getWriter().println("上次访问时间:" + date.toLocaleString());
}
}
}
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
cookie.setMaxAge(60*60*24);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Cookie 的不可跨域名性
很多网站都会向浏览器颁发Cookie,Google会向浏览器颁发Cookie,BaiDu也会向浏览器办法Cookie,那么访问Google的时候会不会也带上BaiDu的Cookie呢?答案是否定的,Google具有不可具有不可跨
域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操
Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。
Cookie的有效期
cookie的有效期是通过setMaxAge来设置的。
- 如果MaxAge为正数,浏览器就会把Cookie写到硬盘中,只要还在MaxAge毫秒之前,登录网址时 Cookie就有效【不论关了电脑还是浏览器】
- 如果Max为负数,Cookie是临时性的,仅在本浏览器中有效,关闭浏览器Cookie就失效了,Cookie也不会写入硬盘中。Cookie默认值就是-1。
- 如果MaxAge为0。则代表删除该Cookie。Cookie没有提供删除Cookie的对应方法,把MaxAae设置为0,则表示删除该Cookie。
Session
什么是Session
Session是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,而session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种形式记录在服务器,这就是session
如果说Cookie 是检查用户身上的“通行证”来确认用户身份,那么Session就是通过检查服务器上的“客户明细表”来确认用户身份。Session相当于在服务器中建立了一张客户明细表。
为什么要使用session
Session比Cookieyao使用方便,Seesion可以解决Cookie解决不了的事情【Session可以存储对象,Cookie只能存储字符串】
Session API
long getCreationTime();; | 获取session被创建的时间 |
---|---|
String getId(); | 获取Session的id |
long getLastAccessedTime(); | 返回Session的最后活跃的时间 |
ServletContext getServletContext(); | 获取ServletContext对象 |
void setMaxInactiveInterval(int var1); | 设置Session超时时间 |
int getMaxInactiveInterval() ; | 获取Session超时时间 |
Object getAttribute(String var1); | 获取Sessino属性 |
Enumeration getAttributeNames(); | 获取session的所有属性名 |
void removeAttribute(String var1); | 移除session属性 |
void invalidate(); | 销毁该Session |
boolean isNew(); | 该session是否为新的 |
Seesion作为域对象
从上面的ApI可以看出Session有着和ServletContext类似的方法,Session也是一个域对象。
Session作为一种记录浏览器状态的机制,只要Session对象没有被销毁,Serlvet之间就可
以通过Session对象实现通讯。
一般来讲,当我们要存进的是用户级别的数据就用Session,那么什么是用户级别的呢?
只要浏览器不关闭希望数据还在,就使用Session来保存。
Session的生命周期和有效期
Session在用户第一次访问服务器Servlet,jsp等动态资源的时候被自动创建,Session对象
保存在内存里,这也就是为什么可以通过request对象获取到Session对象,如果访问HTML等动态资源则不会被创建。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,无论是否对
Session进行读写,服务器都会认为Session活跃了一次。
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为了防止内存溢出,
服务器会把长时间没有活跃的Session删除,这个时间也就是Session的超时时间。
Session的超时时间默认是30分钟,有三种方式可以对Session的超时时间进行修改
第一种方式 在tomcat/conf/web.xml文件中设置,时间值为20分钟,所有的WEB应用都有效。
<session-config>
<session-timeout>20</session-timeout>
</session-config>
第二种方式:在单个的web.xml文件中设置,对单个web应用有效,如果有冲突,以自己的web应用为准。`
<session-config>
<session-timeout>20</session-timeout>
</session-config>
第三种方式:通过setMaxInactiveInterval()方法设置
//设置Session最长超时时间为60秒,这里的单位是秒
httpSession.setMaxInactiveInterval(60);
System.out.println(httpSession.getMaxInactiveInterval());
Session的实现原理
在Servlet3中获取session ,设置一个属性
public class servlet3 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("name","看完博客就要点赞!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
在Servlet4中可以获取到刚才在Servlet3中设置的session属性
public class Servlet4 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String value = (String) session.getAttribute("name");
System.out.println(value);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
但是当我打开另外一个浏览器访问servlet4的时候,却拿不到session3中存进去的属性了。
那么服务器是如何实现一共session为一个浏览器服务的?为什么服务器为不同浏览器提供不同的session?我用Google浏览器访问servlet3存进去的属性,为什么换成360浏览器就取不出来了?
HTTP是无状态协议,Session不能依据HTTP连接来判断是否是同一个用户,于是浏览器想服务器发送了一个名为JESSION的Cookie,它的值是Session的id值,其实Session是依据Cookie来判断是否是同一个用户。
简单来说,Session之所以可以识别不同的用户,依靠的是Cookie。
当我访问Servlet3的时候,服务器会创建一个Session对象,执行程序代码,并自动颁发一个Cookie给浏览器。
当我再使用浏览器访问servlet4的时候,浏览器会把Cookie的值通过Http协议带过去给服务器,服务器就知道用哪一个Seesion
但是当我换一个浏览器访问servlet4的时候,该浏览器并没有Cookie,服务器就不知道用哪一个Session,所以就获取不到值。