背景介绍:
1、cookie的由来:
web开发中,保存web浏览状态的一种方式,http请求是无状态的, 当用户在发送一个请求关得到返回信息之后,客户端与服务器端之间的网络连接就已经断开了, 在下一个请求发送时,服务器无法确定这次请求和上次的请求是否来自同一个客户端。
那时的办法是在请求的页面中插入一个token,并且在下一次请求中将这个token返回(至服务器)。这就需要在form中插入一个包含token的隐藏表单域,或着在URL的qurey字符串中传递该token。这两种办法都强调手工操作并且极易出错。
这些方法的本质都是通过增加一种标记,来标识用户通过浏览器的请求,进行用户的标识。
2、cookie的应用:
最开始是为了购物车功能的实现,一般用来登录状态的验证和购物车之类的功能。
3、cookie的本质:
cookie是一个文本文件,保存在客户端硬盘中(如果设置了cookie的过期时间),或者在用户的浏览器内存中(如果cookie是临时的)。
知识剖析
(一)创建cookie
cookie的创建,在登录成功之后创建,
cookie通常以 name=value格式的字符串来使用,也就是key和value
.setMaxAge:cookie的生命周期,通过设置时间告知浏览器何时删除该cookie
.setDomain:cookie的作用域,默认为创建该cookie的页面所在的域名
.setPath:cookie的使用路径,通过设置路径确定哪一些请求的url,在其http请求的响应头中加入该cookie信息
(二)cookie的验证方式
多数需要登录的站点通常会在你的认证信息通过后来设置一个cookie,之后只要这个cookie存在并且合法,你就可以自由的浏览这个站点的所有部分。
在刚学习cookie时,对cookie的作用很模糊,所以对它的验证方式不是很明白
也就是只基于cookie的作用(记录状态),不涉及它的安全性,安全性是靠程序代码去实现的。也就是还有一个安全性,暂不讨论。
我现在的理解:根据流程来讲,
(1)客户端输入账号、密码登录发送至服务器端;
(2)服务器端验证,登录成功后,创建cookie,设置属性;发送至客户端保存
(3)浏览器在http请求头中加入cookie信息。发送至服务器端
(4)服务器端进行验证
两点详解
第4步中,服务器端的验证是指非空的验证,即cookie是否存在--------非空
具体体现在下面的代码实战中,设置的登录验证拦截器起到的作用
第3步中,在http请求头中加入cookie信息之前,会进行合法性的验证---------合法
主要在这一步的理解上,也就是cookie合法性的验证,浏览器根据http请求的url和cookie的属性进行比对,主要是其中的Domain、Path,
(1)Domain:浏览器会对domain的值与请求所要发送至的域名,做一个尾部比较(即从字符串的尾部开始比较),并且在匹配后发送一个Cookie消息头。
简单来说,cookie与域名相对应,要保证domain的值与请求的url中的域名相同,才会在请求头中添加cookie;
(2)Path:通过将path属性值与请求的URL从头开始逐字符串比较完成的。
简化为,cookie与页面对应,类似于一个拦截器,保证path的值与请求的url中的页面路径相同,才会在请求头中添加cookie;
可以理解为,通过上面两点,来达到只有“cookie中的地址”和“请求指向的地址”一致,该cookie才会添加到该请求上,来确保该cookie是由该程序创建的。
编码实战
主要就是cookie验证登录的一个简单的流程;
客户端访问服务器,服务器调用response.addCookie()方法,产生响应时,会产生set-cookie响应头,将cookie文本发送给客户端,客户端会将cookie文本保存起来,当客户端再次请求服务器时,会产生cookie请求头,将之前服务器发送的cookie信息,再发送给服务器,服务器就可以根据cookie信息跟踪客户端的状态。
1、根据上面的流程,代码练习
(1)addCookie(),在用户登录时,添加cookie,也就是controller中的登录
Cookie namecookie = new Cookie("name", people.getName());// 新建一个Cookie对象
namecookie.setMaxAge(30 * 60);// 设置为30min,生命周期
namecookie.setPath("/u");//设置Cookie的使用路径
response.addCookie(namecookie);// 保存cookie到客户端
(2)登陆成功,客户端保存cookie
(3)通过拦截器,拦截url,实现一个设为用户不登录可以访问,一个设为用户必须登录才可以访问。
2、拦截器-------实现非空的验证
通过实现HandleInterceptor接口,重写里面的方法;
重写preHandle方法,返回的是true,继续下面的方法;如果返回的是false,请求结束
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
Cookie[] cookies = request.getCookies();
if (cookies.length == 0) {
System.out.println("没有cookie==============");
} else {
System.out.println("有cookie=========");
String name = "";
String password = "";
// 遍历cookie如果找到登录状态则返回true执行原来controller的方法
for (Cookie cookie : cookies) {
System.out.println(cookie.getValue());
if (cookie.getName().equals("name")) {
System.out.println("验证成功" + cookie.getValue());
// 在页面显示登录用户
name = cookie.getValue();
request.getSession().setAttribute("name", name);
System.out.println("---------------------" + name);
return true;
}
}
}
// 没有找到登录状态则重定向到登录页,返回false,不执行原来controller的方法
response.sendRedirect("/test");
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
springmvc配置文件配置拦截器
<mvc:interceptors>
<!-- 配置登陆拦截器 -->
<mvc:interceptor>
<!--拦截后台页面的请求-->
<mvc:mapping path="/u/**"/>
<bean class="com.util.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
扩展思考
1、 Http是无状态的短连接,而TCP是有状态的长连接
Http协议(超文本传输协议),应用层
TCP协议(传输控制协议),传输层
Http就是在每次请求完成后就把TCP连接关了,所以是短连接。而我们直接通过Socket编程使用TCP协议的时候,因为我们自己可以通过代码区控制什么时候打开连接什么时候关闭连接,只要我们不通过代码把连接关闭,这个连接就会在客户端和服务端的进程中一直存在,相关状态数据会一直保存着。
参考文献:
https://blog.csdn.net/xingzheouc/article/details/48948513
技能树.IT修真院
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,掌控自己学习的节奏,学习的路上不再迷茫”。
这里是技能树.IT修真院,成千上万的师兄在这里找到了自己的学习路线,学习透明化,成长可见化,师兄1对1免费指导,这里的老大超级帅。快来与我一起学习吧~
你可以直接点击此链接:http://www.jnshu.com/login/1/26712252