Cookie
HTTP协议本身是无状态的。每次信息交流完毕后,服务端和客户端便失去了联系,等下一次访问时,并不知道客户端之前有没有访问。相当于每次都是一次新的访问请求,当应用到登录功能时,每当用户请求一个新的页面,就要重新验证一次用户的身份,这样显得特别麻烦。因此,为了解决这一问题,Cookie应运而生。
Cookie实际上是一小段的文本信息(key-value格式)。客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。
举例:去商家购物,商家(服务端)给你(客户端)一张可以盖章的礼品卡(Cookie),每次购物完成后可以把礼品卡拿给商家盖章。这张礼品卡就可以记录你和商家之间交易的信息。
具体使用
发送cookie
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
Cookie cookie = new Cookie("name", "abc");
cookie.setMaxAge(20);
resp.addCookie(cookie);
resp.getWriter().write("cookie已发送");
}
当访问结束后,在浏览器端可以看到发送过来的cookie
接收cookie
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName()+"---"+cookie.getValue()+"---"+cookie.getPath());
}
}
else {
System.out.println("没有cookie");
}
}
请求完成后,将在控制台打印出cookie的相关信息
如果直接获取cookie(没有发送过cookie)
cookie的相关属性
name:一个cookie的名称
value:一个cookie的值
domain:可以访问此cookie的域名
path:可以访问此cookie的页面路径
Size:此cookie大小
http:cookie的httponly属性,若此属性为True,则只有在http请求头中会有此cookie信息,而不能通过document.cookie来访问此cookie。
secure:设置是否只能通过https来传递此条cookie。
expires/Max-Age:设置cookie超时时间。如果设置的值为一个时间,则当到达该时间时此cookie失效。不设置的话默认是session,意思是cookie会和session一起失效,当浏览器关闭(并不是浏览器标签关闭,而是整个浏览器关闭)后,cookie失效。
可以通过设置cookie的属性值来改变过期时间(单位为秒)
cookie.setMaxAge(int expiry);
(1)当expiry的值为正数时,表示expiry后过期;
(2)当expiry等于0时,表示删除cookie;
(3)当expiry为负数时,表示这是一个临时cookie,仅在本浏览器窗口或本窗口打开的子窗口有效,关闭浏览器后该cookie立即失效。
修改或删除cookie
由于HttpServletResponse对cookie的操作仅提供有addCookie(Cookie cookie),所以当想删除或者修改cookie时,可以通过设置cookie的maxAge来实现。
删除cookie:将cookie的maxAge设置为0,然后再覆盖掉之前的cookie
cookie.setMaxAge(0);
resp.addCookie(cookie);
同样,如果想要修改某cookie,则只需要新建一个同名的cookie覆盖掉之前的即可。但完成这些操作的前提是,新建的cookie,除了value、maxAge之外的属性,其他如name、path、domain等都必须与原来的一样,否则浏览器将视为不同的两个cookie,从而使操作失效。
注意: 客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name和value属性,maxAge属性只被浏览器用来判断Cookie是否过期,而不能用服务端来判断。 我们无法在服务端通过cookie.getMaxAge()来判断该cookie是否过期,maxAge只是一个只读属性,值永远为-1。当cookie过期时,浏览器在与后台交互时会自动筛选过期cookie,过期了的cookie就不会被携带了。
域名限制访问权限
ookie是不可以跨域名的,如a.bb.com和b.bb.com是不可以共享cookie的。若想要共享cookie,可以通过设置cookie的domain属性来实现,如
cookie.setDomain(".bb.com");
路径
浏览器在请求时,会把cookie带回客户端,但是如果有多个cookie,该带谁回去呢,这就需要用到路径了。举例如下:
如果现在有两个cookie,A和B,路径分别为 /demo和 /demo/exp。那么,当访问如下链接时,会出现两种情况
(1)http://localhost/demo,会发送cookie A
(1)http://localhost/demo/exp,会发送cookie A和cookie B
也就是说,当请求某个路径的cookie时,会将其父路径的cookie也发送回去;而在访问父路径时,不会带上子路径的cookie。
Session
Session是另一种记录客户状态的机制,不同的是 Cookie保存在客户端浏览器中,而Session保存在服务器上 。
举例: 去商家购物时,如果商家给你卡片,你完全可以自己盖章,不用到商家去盖章也可以,这就造成了cookie不安全的情况。数据保存在客户端,很不安全。但此时商家改变策略,不给你卡片(cookie),只给你一个卡号(session),去购物时只需要告诉店家卡号,店家便会给你记一次,这样记录保存在商家(服务端),比客户端更为安全。
从某方面讲,其实session是建立在cookie的机制之上的,如果cookie被禁,那么通过cookie的方式便不能实现session,此时需要进行URL地址重写。
具体使用
用如下例子来测试session
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
session.setAttribute("username", "xiaoming");
String sid = session.getId();
PrintWriter out = response.getWriter();
//如果session是新的
if (session.isNew())
{
out.print("新的session,sid="+sid);
}
else
{
out.print("旧的session,sid="+sid);
out.print(session.getAttribute("username"));
}
}
第一次访问,属于最新浏览,打印出sid
第二次访问,可以看到sid是不变的,切打印出了session保存的一个内容
重写URL
当浏览器禁用cookie时,可以采用URL重写机制实现会话保持。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();
session.setAttribute("username", "xiaoming");
String sid = session.getId();
PrintWriter out = response.getWriter();
//如果session是新的
if (session.isNew())
{
String url = response.encodeURL("SendServlet");
System.out.println("新的");
response.sendRedirect(url);
}
else
{
out.print("旧的session,sid="+sid);
out.print(session.getAttribute("username"));
}
}
第一次访问是新的,然后重定向到重写URL的网址
接下来不管怎么刷新,sid一直不变,说明就算禁用了cookie,也还可以通过此方法实现会话保持。