cookie、session和application
https://cloud.tencent.com/developer/article/1493869
前言:
一直想写一篇关于cookie和session的博客,由于种种原因,一直没有整理,这不,今天还就遇到问题了,之前虽然会,但是好久没用又给忘了,结果还得查资料。是时候填坑了,闲话少说,开干。
application
Application用于保存所有用户的公共的数据信息,在这只是提一下,不过多解释。
下面我主要解说cookie和session,不过在解说之前有必要让大家先了解一下HTTP协议和会话跟踪
HTTP协议
协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则
HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。再通俗点讲,Http协议基本是有一个request/response模型也就是请求/响应模型的,通俗讲也就是“一问一答”的模式,浏览器向服务器发起request请求,这就是“问”;服务器收到请求后,返回response响应,这就是“答”。
需要强调的是HTTP是无连接并且是无状态的
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
会话跟踪
在计算机术语中,会话是指一个终端用户与交互系统进行通讯的过程,比如从输入账户密码进入操作系统到退出操作系统就是一个会话过程。会话较多用于网络上,TCP的三次握手就创建了一个会话,TCP关闭连接就是关闭会话。
可能这些官方的话有些新手朋友看了不理解,没关系,我再通俗点,假如你就是用户,你的电脑就是服务器,此时你想访问我的博客园,我的博客园网址是https://www.cnblogs.com/zyx110/,然后你把我的博客园地址复制粘贴到了浏览器页面的地址栏里,敲一下回车键,从你复制粘贴网址到敲击回车键这个过程就是客户端向服务器发送一个请求(request),等你敲击过回车键后,你发现你的浏览器页面跳转到了泰斗贤若如的博客园,这个过程就是服务器给客户端的一个响应(response),再联想上面说到的HTTP的无连接和无状态,客户端和服务器之间只有一次联系,而且“说了下句忘了上句”,还有就是这只是客户端和服务器端间的联系,浏览器的请求(request)与请求之间是没有关系的。但是我们想要开发Web应用,就应该让这些请求之间有关系,这就需要我们在多个request请求之间创建一些联系,这就是会话(session),会话简单点讲就是“要想顺利交谈,需要说了下句想起来上句”,多次HTTP连接间维护用户与同一用户发出的不同请求之间关联的情况称为维护一个会话,所以这些建立联系的request请求是属于某个(会话)session的。
再举个例子吧,可能有些朋友看了上面这些还有点犹豫,不要紧,慢慢理解,理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,你是用户,你在淘宝购买的任何商品都应该放在你的购物车内,不管你是什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无连接无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
cookie
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie 的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie(通行证)。客户端会把Cookie保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
我们访问浏览器的时候,浏览器会发送一个HTTP请求到服务器端;
服务器会发送一个HTTP响应到客户端,其中包括Sst-Cookie,意思就是浏览器建立一个cookie保存服务器指定的内容,比如用户信息和用户操作信息;
浏览器保存好信息之后,下次我们再次访问网站的时候,浏览器再发送HTTP请求到服务器端时都会携带之前保存的cookie;
服务器端会从收到的cookie中识别用户身份,就能让页面为你提供专门属于你的内容了。
比如我们从网站的登陆界面中看到有记住用户名这个选项,你勾选了它以后,登录成功,浏览器就会把你的信息放在cookie里,下次再访问这个网站的时候,服务器就能根据收到的cookie识别出是你,帮你自动登陆,显示专属于你的内容。
session
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录
在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。
思考两个问题:
- 什么东西可以让你每次请求都把SessionId自动带到服务器呢? 显然就是cookie了,如果你想为用户建立一次会话,可以在用户授权成功时给他一个唯一的cookie。当一个
用户提交了表单时,浏览器会将用户的SessionId自动附加在HTTP头信息中,(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionId
所对应的用户。试想,如果没有 SessionId,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。
web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:
- 存储在服务器端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。
- 将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式。
- 如何储存需要的信息? 服务器通过SessionId作为key,读写到对应的value,这就达到了保持会话信息的目的。
session的创建:
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了sessionId,如果已包含则说明以前已经为此客户端创建过session,服务
器就按照sessionId把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含sessionId,则为此客户端创建一个session并且生成一个与此session相关
联的sessionId,sessionId的值是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionId将被在本次响应中返回给客户端保存。
禁用cookie:
如果客户端禁用了cookie,通常有两种方法实现session而不依赖cookie。
- URL重写,就是把sessionId直接附加在URL路径的后面。
- 表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如:
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
Session共享:
对于多网站(同一父域不同子域)单服务器,我们需要解决的就是来自不同网站之间SessionId的共享。由于域名不同(aaa.test.com和bbb.test.com),而SessionId又分别储存
在各自的cookie中,因此服务器会认为对于两个子站的访问,是来自不同的会话。解决的方法是通过修改cookies的域名为父域名达到cookie共享的目的,从而实现SessionId的共
享。带来的弊端就是,子站间的cookie信息也同时被共享了。
cookie和session案例解析(记住我)
package servlet;
import domain.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/*
* 用户登录的Servlet
* */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//接收数据
String username = req.getParameter("username");
String password = req.getParameter("password");
//从ServletContext域中获得保存用户信息集合
List<User> list = (List<User>) this.getServletContext().getAttribute("list");
for (User user:list){
//判断用户名是否正确
if (username.equals(user.getUsername())){
//判断密码是否正确
if (password.equals(user.getPassword())){
//用户名密码都正确
//登录成功
//判断记住用户名复选框是否勾选
String remember = req.getParameter("remember");
if ("true".equals(remember)){
//完成记住用户名的功能
Cookie cookie = new Cookie("username",username);
//设置有效路径
cookie.setPath("/login.jsp");//设置此路径后只能在login.jsp访问cookie
//设置有效时间
cookie.setMaxAge(60*60*24);
//将cookie回写到浏览器
resp.addCookie(cookie);
}
//将用户的信息保存到Session中
req.getSession().setAttribute("user",user);
resp.sendRedirect("/success.jsp");
return;
}
}
}
//登录失败
req.setAttribute("msg","用户名或密码错误!");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException