这篇文章主要作为《深入分析java web技术内幕》这本书中“深入理解Session与Cookie”章节的阅读笔记。强烈推荐这本书,是淘宝大牛许令波写的。这本书是在参加完阿里实习的面试之后开始看的,真是后悔没有提前看啊,面试的好多问题都可以在里面找到答案,虽然很多地方还不是特别懂,不过还是有很多收获。
1 Session和Cookie出现的原因——HTTP的无连接性
因为HTTP使用的是无状态连接,连接只是针对一次请求/响应,那么当用户的第一次请求访问结束后,后端服务器就无法知道下一次来访问的还是不是上次来访问的用户。
Cookie和Session的作用都是为了保持访问用户与后端服务器的交互状态。
2 Cookie
当一个用户通过HTTP访问一个服务器时,这个服务器会将一些Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在符合条件下该用户(浏览器)下次再访问这个浏览器时,数据又会被完整地带回服务器。这样服务器就可以根据Cookie的值来划分访问的用户。
所以说Cookie是一种在客户端保持状态的机制。它是HTTP头中的一个字段。Cookie的所有数据都存在客户端的浏览器中,所以这些Cookie数据是可以被访问到的,通过一些浏览器插件可以看到甚至修改Cookie的值,因此采用Cookie机制会存在一定的安全问题。
不同浏览器对Cookie的大小和数量有一定的限制,超过限制会出现丢弃Cookie的现象,严重影响应用系统的正常使用。当系统大到需要很多Cookie时,就需要考虑Cookie数量和大小限制的这个瓶颈。如果Cookie的量非常大,则可以考虑将Cookie做压缩,压缩方式是将Cookie的多个K/V看成普通的文本,做文本压缩。
但是将值存储在客户端的浏览器中也有一定的优势,在大型的互联网应用系统可能有上百台服务器,这就导致同一个用户的请求可能会分配给不同的服务器处理,因为Cookie机制在用户每次访问时都会将保存在浏览器中的最新值带给处理该请求的服务器,所以不会存在Cookie不一致的问题,Cookie机制可以很好的解决应用的分布式部署问题。
3 Session的三种正常工作方式
1 URL重写(一般在浏览器不支持Cookie的情况下使用)
2 基于Cookie
3 基于SSL
主要介绍基于Cookie的工作方式
用Session机制保持客户端和服务器的交互状态时,同一个客户端每次和服务器交互不需要传回所有的Cookie值,而只需回传一个ID用来标示客户端的身份,这个ID通常是名为JSESIONID的一个Cookie,其它会话期间的信息都保存在服务器端的Session对象中。
所以Session是一种在服务器端保持状态的机制。
因为Session是将数据保存在服务器端,只是通过Cookie传递一个SessionID,所以安全性要高很多。但是当一个应用系统有几百台服务器时,需要解决session对象在多个服务器之间共享的问题。
书中还提到了结合Cookie和Session各自优势的分布式Session框架,并没有特别理解,先做一个标记,后面理解之后再补充。
4 利用session解决表单重复提交问题:
要防止表单重复提交,就要表示用户的每一次访问请求,可以在用户请求表单域时增加一个隐藏表单项,并且每次生成一个唯一的token,同时将这个token保存在用户的session中,等用户提交时检查这个token与session中的token是否一致。如果一致,则处理请求,并且将session中的token删除,如果不一致则判断为重复提交。
表单中增加token隐藏域 <%String tokenValue = new Date().getTime()+" "; %>
<form action="loginServlet" method="post">
<input type="hidden" name="token" value="<%= tokenValue%>">
<% session.setAttribute("token", tokenValue); %>
name:<input type="text" name="name">
<input type="submit" value="提交">
</form>
服务器端接收到表单提交的数据时,先进行判断,如果一致,则处理请求,并且将session中的token删除,如果不一致则判断为重复提交。
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String tokenValue = req.getParameter("token");
HttpSession session = req.getSession();
Object token = session.getAttribute("token");
System.out.println(token);
System.out.println(tokenValue);
if(token != null && token.equals(tokenValue)){
session.removeAttribute("token");
}else{
resp.sendRedirect("fail.jsp");
return;
}
String name = req.getParameter("name");
System.out.println("name:"+name);
resp.sendRedirect("success.jsp");