----其实这是个基本的问题,奈何自己对他们了解不深,特开此贴,加深理解。
Q1:为什么要有cookie和session?
A1:因为http是个无状态协议,也就是说在一次会话中我做了啥事,我不会记住,所以得有个地方记录一下这次会话的状态,而cookie和session就是来记录会话状态的技术。
那么先来聊聊cookie。
Q2:cookie是由谁产生?什么时候产生?保存在哪里?
A2:cookie是由服务器产生,保存在客户端的一种信息载体。这个载体中存放的是会话状态的信息。只要cookie没有被清空,或者说cookie没有失效,那么保存的会话状态信息就有效。
用户在提交一次请求后,由服务器生成cookie,并将其封装在响应头中,以响应的形式发送给客户端。客户端在接收到这个响应后,将cookie保存在客户端,当客户端再次发送同类请求后,在请求中会携带保存在客户端的cookie数据,发送到服务端,由服务器进行会话跟踪。
Q3:为什么要有session?
A3:因为你cookie是保存在客户端是不安全的,比如说你的用户名或者密码都在cookie中,很可能会被别人盗取,得了吧,你每次也别拿着你身份信息了,你只需要拿个身份证号码(JSESSIONID)就行了,你的身份信息我给你保存到服务器上了,这样在一个会话中,我(服务器)就知道你是谁了,提高了安全性。
Q4:session工作的原理是什么?
(1)写入session列表
当前应用中的session是以map的形式进行管理的,这个map称为sessionMap,该map的key是一个32位长度的随机字符串,称之为JSessionID,value则是一个对象的引用。
当用户第一次提交请求时,服务端会调用getSession()方法生成一个Map.Entry对象,key为一个32位长度的随机字符串,value就是一个HttpSession对象。所以,你就可以认为你的会话中的信息就保存在一个map中。
(2)在将session信息保存到map中后,系统还自动将“JESSIONID”作为name,将32位长度的随机字符串作为value,以cookie的形式放到响应头中,并随着响应发送到客户端。
(3)当客户端接收到这个cookie后会将他保存到浏览器中的缓存中,即当客户端浏览器不关闭,浏览器中的缓存就不会失效。当用户第二次提交请求时会携带上缓存中的cookie,伴随着请求中的头部信息一起发送给服务端。
Q4:你老是说session依赖cookie你怎么证明呢?
A4:其实我也是一直听别人说session依赖cookie,session依赖cookie,session依赖cookie,那么终于给证明了,其实很简单,你debug进去就行了,豁然开朗的感觉。
上代码
@RequestMapping("/setsession")
public String setsession(HttpServletRequest request,HttpServletResponse response){
String username=request.getParameter("username");
request.setAttribute("username",username);
HttpSession session= request.getSession();
session.setAttribute("user",username);
return "some: "+username;
}
看到.getSession()方法了吧
getSession()
getSession(true);
HttpSession getSession(boolean create)
getSession(create)
doGetSession(create)
protected Session doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
Context context = getContext();
if (context == null) {
return (null);
}
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
return (session);
}
// Return the requested session if it exists and is valid
Manager manager = context.getManager();
if (manager == null) {
return (null); // Sessions are not supported
}
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) {
session = null;
}
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
session.access();
return (session);
}
}
// Create a new session if requested and the response is not committed
if (!create) {
return (null);
}
if (response != null
&& context.getServletContext()
.getEffectiveSessionTrackingModes()
.contains(SessionTrackingMode.COOKIE)
&& response.getResponse().isCommitted()) {
throw new IllegalStateException(
sm.getString("coyoteRequest.sessionCreateCommitted"));
}
// Re-use session IDs provided by the client in very limited
// circumstances.
String sessionId = getRequestedSessionId();
if (requestedSessionSSL) {
// If the session ID has been obtained from the SSL handshake then
// use it.
} else if (("/".equals(context.getSessionCookiePath())
&& isRequestedSessionIdFromCookie())) {
/* This is the common(ish) use case: using the same session ID with
* multiple web applications on the same host. Typically this is
* used by Portlet implementations. It only works if sessions are
* tracked via cookies. The cookie must have a path of "/" else it
* won't be provided for requests to all web applications.
*
* Any session ID provided by the client should be for a session
* that already exists somewhere on the host. Check if the context
* is configured for this to be confirmed.
*/
if (context.getValidateClientProvidedNewSessionId()) {
boolean found = false;
for (Container container : getHost().findChildren()) {
Manager m = ((Context) container).getManager();
if (m != null) {
try {
if (m.findSession(sessionId) != null) {
found = true;
break;
}
} catch (IOException e) {
// Ignore. Problems with this manager will be
// handled elsewhere.
}
}
}
if (!found) {
sessionId = null;
}
}
} else {
sessionId = null;
}
session = manager.createSession(sessionId);
// Creating a new session cookie based on that session
if (session != null
&& context.getServletContext()
.getEffectiveSessionTrackingModes()
.contains(SessionTrackingMode.COOKIE)) {
Cookie cookie =
***ApplicationSessionCookieConfig.createSessionCookie(
context, session.getIdInternal(), isSecure());
response.addSessionCookieInternal(cookie);***
}
if (session == null) {
return null;
}
session.access();
return session;
}
=============================================
ApplicationSessionCookieConfig.createSessionCookie(
context, session.getIdInternal(), isSecure());
response.addSessionCookieInternal(cookie)
==================================================
doGetSession中有上面这个代码,这个就是session中利用了cookie的铁证。
Q5:我如果客户端禁用了cookie,就是我客户端不能保存你服务端给我的身份证了,并且我也不能携带这些信息了。这时候用session机制该怎么办?
A5:佛说,URL重写。至于什么是URL重写你可以谷歌和问度娘。