Cookie和Session

183 阅读6分钟

会话技术

什么是一次会话

用户通过浏览器访问一个网站,间接访问了多条超链接,直到他关闭浏览器的这个过程 称为一次会话。

通过会话技术,可以实现 下次免登陆功能,商品推荐功能,购物车功能等。

Cookie

简介

Cookie的提出

HTTP协议是无状态的,一旦双方的数据提交完,连接就会断开,再次交互时需要重新建立新连接。而有些应用需要服务器掌握客户端状态,因此便有了Cookie。

Cookie的流程

当浏览器访问服务器时,若服务器需要记录用户状态,就可以在 返回给客户端的响应中放入Set-cookie。浏览器收到后会保存Cookie,当它再次访问服务器时,就会顺带把Cookie放入请求中。

Cookie不可跨域名性

每个域名都有对应的Cookie,服务器只会发送它对应域名的Cookie。

Cookie的相关类和方法

(1)Cookie类可以创一个Cookie对象。该类的部分代码如下所示:

public class Cookie implements Cloneable, Serializable {
    private final String name;
    private String value;
    private String path;
    /*
        cookie最大生存时间,单位是秒。默认值为-1,
        表示仅在本浏览器有效,一旦关闭浏览器cookie就会失效,不会写到硬盘中。
        若其值为0,表示删除该cookie(Cookie机制没有提供删除Cookie对应的方法)。
    */
    private int maxAge = -1;
    /*
        Cookie是不可跨域名的,即便是同一级域名,不同二级域名也是不能交接的。
        比如www.goole.com和www.image.goole.com的cookie是不能访问的。
        但通过domain变量可以设置可访问域名级别,例如cookie.setDomain(".goole.com");
        这样只要一级域名是.goole.com的都可以访问
    */
    private String domain;
    public Cookie(String name,String value);
    //省略

(2)response对象的addCookie()方法可以在响应头中加入一个Set-Cookie;

(3)request对象的getCookies()方法可以获取客户端提交的Cookie

示例

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        Cookie cookie = new Cookie("key", "C2y");
        
        cookie.setMaxAge(1000);
        resp.addCookie(cookie);
    }

如果放入的value值是中文,则需要对中文进行编码。

String value = "中文";
Cookie cookie = new Cookie("key", URLEncoder.encode(value, "UTF-8"));

取出cookie值时需要进行解码

    Cookie[] cookies = req.getCookies();
    for (int i = 0; cookies != null && i < cookies.length; i++) {
        String key = cookies[i].getName();
        String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");
    }

Cookie的路径

一般情况下所有Servlet都可以使用Cookie,Cookie类的成员变量path表示允许访问Cookie的路径。

Cookie cookie = new Cookie("key", "value");
cookie.setPath("/AS");
cookie.setMaxAge(1000);
res.addCookie(cookie);

printWriter.write("该Cookie只有AS可以获取");

Session

简介

Session是另一种记录浏览器状态的机制,前面介绍的Cookie是保存在浏览器,而Session是保存在服务器中。

生命周期和有效期

(1)当用户第一次访问Tomcat里的Servlet,jsp等动态资源时,Session就会自动创建,它保存在内存里。每当用户继续访问,服务器都会更新Session的最后访问时间。

(2)Session的超时时间可以防止Session过多导致内存溢出,服务器会把长时间没有活跃的Session从内存中删除,默认为30分钟。

超时时间可以在单个web.xml文件中设置,这对作用于单个web应用

<session-config>
    <session-timeout>20</session-timeout>
</session-config>   

此外还可以通过setMaxInactiveInterval()方法设置,单位是秒。

(3)session周期是指不活动的时间,每当用户访问一次session,则会重新计时。而cookie是按累计时间来算,不管用户有没有访问过cookie。

实现原理

(1)当浏览器第一次请求服务器时,服务器会创建对应的session,然后将此session的唯一标识信息 SessionID 返回给浏览器。

(2)浏览器接收到服务器返回的SessionID 信息后,放入Cookie 中。当浏览器第二次访问服务器时,服务器会从cookie中取出sessionID,根据ID查找对应Session 信息,根据该信息判断是哪个用户,执行操作。

常用方法

long getCreationTime();//获取Session被创建时间
long getLastAccessedTime();//返回Session最后活跃的时间
ServletContext getServletContext();
void setMaxInactiveInterval(int var1);//设置Session超时时间
void setAttribute(String var1, Object var2);
Object getAttribute(String var1);
void invalidate(); //销毁该Session对象

示例

@WebServlet("/MS")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession httpSession = req.getSession();
        httpSession.setAttribute("name", "C2y");
        httpSession.setAttribute("age", 18);
        System.out.println(httpSession.getId());
        resp.sendRedirect("/AS");
        
    }
}

@WebServlet("/AS")
public class AnoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession httpSession = req.getSession();
        System.out.println(httpSession.getId());
        System.out.println("name: "+ httpSession.getAttribute("name"));
        System.out.println("age:" + httpSession.getAttribute("age"));
    }
}

此时从session取出的值是正常的,且两次输出的sessionID是相同的。

此外还可以发现,服务器向浏览器还发送了一个名为JESSIONID的Cookie,它的值是Session的id值。Session通过这个cookie来判断是否是同一个用户。这个cookie仅供当前浏览器使用,不会存放在硬盘中。

当浏览器禁用了Cookie

当浏览器禁用了cookie,同样运行上面的程序,那么两个servlet输出的sessionID是不同,且取出的两个值是不正常的。

但我们可以通过URL地址重写,HttpServletResponse类提供了两个URL地址重写的方法:

  • encodeURL(String url)
  • encodeRedirectURL(String url)
@WebServlet("/MS")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //此部分代码不变
        resp.sendRedirect(resp.encodeURL("/AS"));
    }
}

这样如果浏览器不支持Cookie,那么重写的URL地址后带有sessionID。

此时取出的两个值和两个Servlet的SessionID都和预期一样。

Session和Cookie的区别

(1)存储的值

Cookie只能存储字符串,对于非ASCII字符串还要对其编码;

Session可以存储任何类型的数据。

(2)隐私安全

Cookie存储在浏览器中,对客户端是可见的。信息容易泄露出去;Session存储在服务器上,不存在敏感信息泄露问题。

(3)有效期

只要maxAge属性为正数,则Cookie保存在硬盘中,即便关闭浏览器,Cookie还是存在的;而Session的保存在服务器中,不过Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但会失效。

(4)浏览器支持

若浏览器禁用了Cookie,则Cookie是无用的;但Session可以通过URL地址重写来进行会话跟踪。

(5)跨域名

Cookie可以设置domain属性来实现跨域名;而Session只在当前的域名内有效,不可夸域名


参考资料

Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】

Servlet第五篇【介绍会话技术、Cookie的API、详解、应用】