目录
- Session
- 概述
- 原理
- session使用
- 获取session
- Session保存数据
- Session获取数据
- Session移除数据
- 应用
- Session & Request 区别
- 总结
- Session生命周期
- 浏览器禁用Cookie解决方案
- 浏览器禁用Cookie后果
- URL重写
- 实现URL重写
问题引入
- HTTP协议是无转态的,不能保存提交的信息
- 如果用户发来一个新的请求,服务器无法知道它是否与上次的请求联系
- 对于那些需要多次提交数据才能完成的web操作,比如登录,就难以完成
概念
将浏览器与web服务器之间多次交互当做一个整体来处理,并且多次交互所涉及的数据(状态)保存下来
状态管理分类
- 客户端状态管理技术:将转态保存在客户端,代表性的是Cooklie技术
- 服务器状态管理技术:将状态保存在服务器端,代表性的是session技术(服务器传递session时需要使用Cookie的方式)和application
Cookie
- Cookie是浏览器访问Web服务器某个资源时,由Web服务器在HTTP响应消息头中附带传送给浏览器的小段数据
- 一旦Web服务器保存了某个Cookie,那么它在以后每次访问该Web服务器时,都应在HTTP请求中将这个Cookie回传给Web服务器
- 一个Cookie主要由标识该信息的名称name和值value组成
Cookie的创建、获取、修改
Cookie创建
public class CookieServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
doPost(req, resp); | |
} | |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
//服务端创建Cookie对象 | |
Cookie cookie = new Cookie("username","weishuo"); | |
//设置Cookie的访问路径 | |
cookie.setPath("/Servlet_Projects_war/get"); | |
//设置Cookie的有效期 >0有效期,单位秒 =0浏览器关闭 <0内存存储 默认-1 | |
cookie.setMaxAge(60*60); //1小时 | |
//添加到response对象中,将Cookie响应给客户端 | |
resp.addCookie(cookie); //将Cookie添加到response对象中,响应给客户端 | |
} | |
} |
Cookie获取
public class GetServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
//通过request对象获取所有的cookie | |
Cookie[] cookies = req.getCookies(); | |
if (cookies!=null){ //判断cookies数组是否为空,避免空指针异常 | |
//通过循环遍历Cookie | |
for (Cookie cookie : cookies) { | |
System.out.println(cookie.getName() + ":" + cookie.getValue()); | |
} | |
} | |
} | |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
doGet(req, resp); | |
} | |
} |
Cookie修改
如果修改Cookie的name和有效路径会新建cookie,而改变Cookie值,有效期会覆盖原有的Cookie
public class CookieServlet2 extends HttpServlet { | |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
doPost(req, resp); | |
} | |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
//服务端创建Cookie对象 | |
Cookie cookie = new Cookie("username","given"); | |
//设置Cookie的访问路径 | |
cookie.setPath("/Servlet_Projects_war/get"); | |
//设置Cookie有效期 | |
cookie.setMaxAge(60*60*24*7); //7天 | |
//添加到response对象中,将Cookie响应给客户端 | |
resp.addCookie(cookie); | |
} | |
} |
Cookie编码与解码
Cookie默认不支持中文
,只能包含ASCII字符
,所以Cookie需要对Unicode字符进行编码,否则会出现乱码
- 编码可以使用
java.net.URLEncoder类
的encode(String str,String encoding)
方法 - 解码使用
java.net.URLDecoder类
的decode(String str,String encoding)
方法
//Cookie设置 | |
public class CookieServlet3 extends HttpServlet { | |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
doPost(req, resp); | |
} | |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
//服务端创建Cookie对象,使用Cookie编码 | |
Cookie cookie = new Cookie(URLEncoder.encode("姓名","UTF-8"),URLEncoder.encode("张三","UTF-8")); | |
//设置Cookie的访问路径 | |
cookie.setPath("/Servlet_Projects_war/get"); | |
//设置Cookie有效期 | |
cookie.setMaxAge(600); | |
//添加到response对象中,将Cookie响应给客户端 | |
resp.addCookie(cookie); | |
} | |
} | |
//Cookie读取 | |
public class GetServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
//通过request对象获取所有的cookie | |
Cookie[] cookies = req.getCookies(); | |
if (cookies!=null){ //判断cookies数组是否为空,避免空指针异常 | |
//通过循环遍历Cookie | |
for (Cookie cookie : cookies) { | |
//使用Cookie解码 | |
System.out.println(URLDecoder.decode(cookie.getName(),"UTF-8") + ":" + URLDecoder.decode(cookie.getValue(),"UTF-8")); | |
} | |
} | |
} | |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | |
doGet(req, resp); | |
} | |
} |
总结
Cookie优点
可配置到期规则Cookie是一种基于文本的轻量级结构,包含简单的键值对Cookie默认在过期之前是可以一直存在在客户端浏览器上
Cookie的缺点
大小受到限制,浏览器对Cookie大小有4K,8K字节限制用户配置为禁用,用户禁用了浏览器或客户端接受Cookie的能力Cookie可能被篡改,存在潜在风险
Session
概述
- Session用于记录用户的状态,Session指的是一段时间,单个客户端与web服务器的一连串交互过程
- 一个Session中,客户可能会多次请求访问同一个资源,也可能请求访问各种不同的服务器资源
原理
Tip:
Session和Cookie都是由服务器端创建
- 服务器为每一次会话分配一个Session对象
- 同一个浏览器发起的多次请求,同属于一次会话(Session)
- 首次使用Session,服务器自动创建Session,并且创建Cookie存储SessionID发送回客户端
session使用
Session作用域:拥有存储数据的空间,作用范围是一次会话有效
- 一次会话是使用同一浏览器发送到多次请求,浏览器关闭则会话结束
- 可以将数据存入Session中,一次会话的任意位置进行获取
- 可以传递任何数据(基本数据类型、对象、集合、数组)
获取session
//获取Session对象 | |
HttpSession session = request.getSession(); | |
System.out.println("id"+session.getId()); //唯一标识 | |
package com.woniu.sessions; | |
import javax.servlet.*; | |
import javax.servlet.http.*; | |
import javax.servlet.annotation.*; | |
import java.io.IOException; | |
public class Servlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
//通过request对象获取session对象 | |
HttpSession session = request.getSession(); | |
System.out.println(session.getId()); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doGet(request, response); | |
} | |
} |
Session保存数据
- 保存数据到session中
setAttribute(属性名,Objects);
session.setAttribute("key",value);//以键值对形式存储在session作用域中
Session获取数据
- 获取session中数据
getAttribute(属性名);
session.getAttribute("key"); //通过String类型的key访问Object类型的value
Session移除数据
- 从Session中删除数据
removeAttribute(属性名);
session.removeAttribute("key");//通过移除session作用域中的值
应用
- Servlet类
public class Servlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
//通过request对象获取session对象 | |
HttpSession session = request.getSession(); | |
//使用session保存数据 | |
session.setAttribute("username","given"); | |
//通过产生的session对象获取sessionId | |
System.out.println(session.getId()); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doGet(request, response); | |
} | |
} |
- GetValueServlet类
public class GetValueServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doPost(request, response); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
HttpSession session = request.getSession(); | |
String username = (String) session.getAttribute("username"); | |
System.out.println("从session中获得了" + username); //从session中获得了given | |
} | |
} |
- RemoveServlet类
public class RemoveServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doPost(request, response); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
HttpSession session = request.getSession(); | |
session.removeAttribute("username"); | |
} | |
} |
- 结果
543D0EA33CB586691A02C00564E34CEA
从session中获得了given
从session中获得了null
Session & Request 区别
- request是一次请求有效,请求改变,则request改变
- session是一次会话有效,浏览器改变,则session改变
SessionServlet类
public class SessionServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
//通过request对象获取session对象 | |
HttpSession session = request.getSession(); | |
//使用session保存数据 | |
session.setAttribute("username","given"); | |
//使用request保存数据 | |
request.setAttribute("password",123456); | |
//重定向跳转到/getValue | |
response.sendRedirect("/Servlet_Projects_war/getValue"); | |
//通过产生的session对象获取sessionId | |
System.out.println(session.getId()); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doGet(request, response); | |
} | |
} |
GetValueServlet类
public class GetValueServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doPost(request, response); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
HttpSession session = request.getSession(); | |
String password = (String) request.getAttribute("password"); | |
System.out.println("从request中获得了" + password); | |
String username = (String) session.getAttribute("username"); | |
System.out.println("从session中获得了" + username); //从session中获得了given | |
} | |
} |
结果
从request中获得了null | |
从session中获得了given |
总结
sendRedirect跳转时,地址栏发生改变,代表客户端重新发送请求,属于两次请求;response没有作用域,两次request请求中的数据无法共享;而session只要浏览器不关闭属于一次会话,一次会话中浏览器数据可以共享
Session生命周期
- 开始:第一次使用到Session的请求产生,则创建Session
- 结束
- 浏览器关闭,则失效
- Session超时,则失效
- session.SetMaxInactivelnterval(seconds); 设置最大有效时间(单位/秒)
- 手工销毁,则失效
- session.invalidate(); 登录退出、注销
LifeSessionServlet类
public class LifeSessionServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doPost(request, response); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
//获取session | |
HttpSession session = request.getSession(); | |
//设置session有效过期时间为10s | |
session.setMaxInactiveInterval(10); | |
//通过产生的session对象获取sessionId | |
System.out.println(session.getId()); | |
} | |
} |
GetSessionServlet类
public class GetSessionServlet extends HttpServlet { | |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
doPost(request, response); | |
} | |
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | |
//获取session | |
HttpSession session = request.getSession(); | |
System.out.println(session.getId()); | |
//手工销毁,立即失效 | |
//session.invalidate(); | |
} | |
} |
结果
浏览器输入/life,获取到的sessionId | |
71A9B2141F22840E0BE7EA67B49EC9B3 | |
10秒内,浏览器输入/getSession,获取到的sessionId | |
71A9B2141F22840E0BE7EA67B49EC9B3 | |
10秒后,浏览器输入/getSession,获取到的sessionId | |
EDF2E31978DE8295486C2657016F5202 |
浏览器禁用Cookie解决方案
浏览器禁用Cookie后果
服务器在默认情况下,会使用Cookie的方式将sessionID发送给服务器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器使用如URL重写这样的方式来发送sessionID
URL重写
浏览器在访问服务器上的某个地址时,不再使用原来的那个地址,而是使用经过改写的地址(即在原来的地址后面加上sessionID)
实现URL重写
- response.encodeRedirectURL(String url); //生成重写的URL
//实现URL重写 | |
String url = response.encodeRedirectURL("/Servlet_Projects_war/getSession"); | |
//输出URL重写地址 | |
System.out.println(url); | |
//重定向转发 | |
response.sendRedirect(url); |
结果
重写URL地址 | |
/Servlet_Projects_war/getSession;jsessionid=A38B1C92B9CDE10F6ED5E7AA19E919F0 | |
浏览器输入/life,获取到的sessionId | |
A38B1C92B9CDE10F6ED5E7AA19E919F0 | |
重定向转发地址:/Servlet_Projects_war/getSession,获取到的sessionId | |
A38B1C92B9CDE10F6ED5E7AA19E919F0 |