前言
HTTP协议是一个无状态协议,什么是无状态协议呢? Web应用程序无法区分收到的不同的HTTP请求是否是同一个浏览器发出的。
在Web应用程序中,Servlet和客户的通信采用“请求/响应”的模式。那服务器又是如何分别不同用户的呢?例如:当一个用户登录成功后,如果他继续访问其他页面,Web程序如何才能识别出该用户身份?
为了跟踪用户状态, Servlet容器提供了Session机制用以跟踪用户。服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。
什么是Session机制?
Session相当于程序在服务器上建立的一份客户档案,当程序需要为某个客户端的请求创建一个Session时,服务器首先检查这个客户端的请求里是否包含了一个Session标识(即SessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过Session,服务器就按照SessionId把这个Session检索出来使用。如果客户请求不包含sessionId,会自动获得一个Session ID。并本次响应中返回给客户端保存。
我们把这种基于唯一ID识别用户身份的机制称为Session。如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。一次Session会话中往往包含着若干次request请求。
JavaEE的Servlet机制内建了对Session的支持。当我们需要获取Session时,可以通过request请求对象的getSession()方法。例如;
HttpSession session=request.getSession();
服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。在Servlet中第一次调用request.getSession()时,Servlet容器自动创建一个Session ID,然后通过一个名为JSESSIONID的Cookie发送给浏览器:
例如运行如下代码:
@WebServlet("/text_session.do")
public class TextSessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("TextSessionServlet被GET到");
// 第一次在访问Session时,服务器会创建Session
// 并根据Session_ID,创建一个名称为"JSESSIONID"的Cookie,将Session_ID保存在Cookie
// 将该Cookie响应回至浏览器保存
// 接下来的每次发起请求时,客户端浏览器都会在请求中,添加JESSIONID
// 用于服务器确认"身份"
HttpSession session =req.getSession();
System.out.println(session.getId());
}
}
控制台结果:
网页请求头所在第一次创建Session返回JSESSIONID:
Cookie
实际上,Servlet提供的HttpSession本质上就是通过一个名为JSESSIONID的Cookie来跟踪用户会话的。除了这个名称外,其他名称的Cookie我们可以任意使用。
创建一个新Cookie时,除了指定名称和值以外,通常需要设置setPath("/"),浏览器根据此前缀决定是否发送Cookie。如果一个Cookie调用了setPath("/user/"),那么浏览器只有在请求以/user/开头的路径时才会附加此Cookie。通过setMaxAge()设置Cookie的有效期,单位为秒,最后通过resp.addCookie()把它添加到响应。
通过创建Cookie,我们可以实现在客户端浏览器中存储数据的目的,例如保存用户名和密码。在Chrome浏览器中,单个 Cookie的长度不能超过 4069 个字符(包括 name,但不包括 = 号)。
我们可以在浏览器看到服务器发送的Cookie,以百度为例:
创建Cookie对象
:
@WebServlet("/text_cookie.do")
public class TextCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象
Cookie cookie1=new Cookie("phone_number", "12323234545");
Cookie cookie2=new Cookie("name", "xiaoming");
Cookie cookie3=new Cookie("sex", "boy");
Cookie cookie4=new Cookie("height", "188cm");
cookie1.setMaxAge(24*24*60*7);//设置过期时间,单位为秒
cookie2.setMaxAge(24*24*60*7);//设置过期时间,单位为秒
cookie3.setMaxAge(24*24*60*7);//设置过期时间,单位为秒
cookie4.setMaxAge(24*24*60*7);//设置过期时间,单位为秒
//响应
resp.addCookie(cookie1);//添加至响应头
resp.addCookie(cookie2);//添加至响应头
resp.addCookie(cookie3);//添加至响应头
resp.addCookie(cookie4);//添加至响应头
}
}
如果我们要读取Cookie
,例如,在TextCookieServlet
中,读取Cookie
以获取用户设置的语言,可以写一个方法如下:
@WebServlet("/text_get_cookie.do")
public class TextGetCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("测试获取cookie");
Cookie[] cookies=req.getCookies();
if (cookies!=null) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
System.out.println(cookie.getValue());
System.out.println();
}
}
}
}
观察控制台:
所以,读取Cookie
主要依靠遍历HttpServletRequest
附带的所有Cookie