会话技术: Cookie 和 Session

会话技术

会话技术:从浏览器开始访问服务器,到关闭浏览器,这期间发生了许多次请求和响应,这个过程就叫做一次会话。

Cookie 和 Session 都是处理会话技术的两种具体实现,Cookie将数据保存在客户端,Session将数据保存在服务器端。

Cookie技术

1.Cookies是存储在客户机的文本文件,可以保存一系列的信息。通常服务器有三个步骤来识别不同的客户机:
  服务器脚本发送一系列cookies至浏览器。比如名字,年龄,ID号码等等。
  浏览器在本地机中存储这些信息。
  当下一次浏览器发送任何请求至服务器时,它会同时将这些cookies信息发送给服务器,然后服务器使用这些信息来识别用户或者做某些其它事情。

2.Cookies通常在HTTP信息头中设置(虽然JavaScript能够直接在浏览器中设置cookies)。在JSP中,设置一个cookie需要发送如下的信息头给服务器:

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=tutorialspoint.com
Connection: close
Content-Type: text/html

Set-Cookie信息头包含一个键值对,一个GMT(格林尼治标准)时间,一个路径,一个域名。键值对会被编码为URL。有效期域是个指令,告诉浏览器在什么时候之后就可以清除这个cookie。

3.如果浏览器被配置成可存储cookies,那么它将会保存这些信息直到过期。如果用户访问的任何页面匹配了cookie中的路径和域名,那么浏览器将会重新将这个cookie发回给服务器。浏览器端的信息头长得就像下面这样:

GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz

 

4.Cookie 对象常用的方法

public void setDomain(String pattern) 设置cookie的域名,比如w3cschool.cc
public String getDomain() 获取cookie的域名,比如w3cschool.cc
public void setMaxAge(int expiry) 设置cookie有效期,以秒为单位,默认有效期为当前session的存活时间。如果不设置,那么只在内存中处理此Cookie,不保存到磁盘,浏览器关闭后消失。
public int getMaxAge() 获取cookie有效期,以秒为单位,默认为-1 ,表明cookie会活到浏览器关闭为止
public String getName() 返回 cookie的名称,名称创建后将不能被修改
public void setValue(String newValue) 设置 cookie的值
public String getValue() 获取cookie的值
public void setPath(String uri) 设置cookie 的路径,默认为当前页面目录下的所有URL,还有此目录下的所有子目录
public String getPath() 获取cookie 的路径
public void setSecure(boolean flag) 指明cookie是否要加密传输
public void setComment(String purpose) 设置注释描述 cookie的目的。当浏览器将cookie展现给用户时,注释将会变得非常有用
public String getComment() 返回描述cookie目的的注释,若没有则返回null

5.使用JSP设置cookie包含三个步骤:

(1)创建一个Cookie对象: 调用Cookie的构造函数,使用一个cookie名称和值做参数,它们都是字符串。
Cookie cookie = new Cookie("key","value");
注意,名称和值中都不能包含空格或者如下的字符:
[ ] ( ) = , " / ? @ : ;
(2)设置有效期:调用setMaxAge()函数表明cookie在多长时间(以秒为单位)内有效。下面的操作将有效期设为了24小时。
cookie.setMaxAge(60*60*24);
(3) 将cookie发送至HTTP响应头中:调用response.addCookie()函数来向HTTP响应头中添加cookies。
response.addCookie(cookie);

6.删除Cookies
删除cookies非常简单:从request中取得已经存在的cookie,将其有效期设置为0,然后再重新添加进响应头中。

7.Cookie 注意事项

setDomain与getDomain方法,用于设置和取得Cookie对应的域名,目前浏览器检测到此值,出于安全考虑,会认为该cookie是一个第三方Cookie而拒收。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
删除cookie时,path必须一致,否则不会删除(浏览器通过cookie的name+path来标识一个cookie)
如果设置了不缓存对象,Cookie 也是不能保存到磁盘中的,因此要保存Cookie,不能使用下面的代码,如果界面没有显示,可以刷新页面更新数据。
  response.setHeader("Expirse", "0");
  response.setHeader("Cache-Control", "no-cache");
  response.setHeader("Pragma", "no-cache");

8.实例演示显示上次访问时间

Cookie cookie = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
  for (Cookie c : cookies) {
    if (c != null && LAST_VISIT_TIME.equals(c.getName())) {
    cookie = c;
    break;
    }
  }
}
if (cookie != null) {
  try {
    String time = cookie.getValue();
    String s = "上次访问的时间是:" + new Date(Long.parseLong(time)).toString();
    response.getOutputStream().write(s.getBytes());
  } catch (Exception e) {
  }
} else {
  response.getOutputStream().write("欢迎您光临本站!".getBytes());
}

cookie = new Cookie(LAST_VISIT_TIME, new Date().getTime() + "");
response.addCookie(cookie);

 

9.实例显示浏览记录的Cookie

package com.john.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MainServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        
        PrintWriter out = response.getWriter();
        String s = "<a href='/HelloWeb/servlet/DetailServlet?id=1'>第一个</a><br>";
        out.write(s);
        s = "<a href='/HelloWeb/servlet/DetailServlet?id=2'>第二个</a><br>";
        out.write(s);
        s = "<a href='/HelloWeb/servlet/DetailServlet?id=3'>第三个</a><br>";
        out.write(s);
        s = "<a href='/HelloWeb/servlet/DetailServlet?id=4'>第四个</a><br>";
        out.write(s);

        Cookie cookie = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie tempCookie : cookies) {
                if (DetailServlet.KEY_IDS.equals(tempCookie.getName())) {
                    cookie = tempCookie;
                    break;
                }
            }
        }
        if (cookie != null) {
            out.write("浏览记录为:" + cookie.getValue());
        } else {
            out.write("没有浏览记录!");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        doGet(request, response);
    }
}
package com.john.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DetailServlet extends HttpServlet {

    public static final String KEY_IDS = "ids";

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        response.setHeader("Expirse", "0");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        String id = request.getParameter("id");

        Cookie cookie = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie tempCookie : cookies) {
                if (KEY_IDS.equals(tempCookie.getName())) {
                    cookie = tempCookie;
                    break;
                }
            }
        }

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("detail....." + id);

        if (cookie == null) {
            cookie = new Cookie(KEY_IDS, id);
        } else {
            cookie.setValue(getNewId(cookie.getValue(), id, 3));
        }
        cookie.setMaxAge(3600 * 24);
        cookie.setPath(request.getContextPath());
        response.addCookie(cookie);
    }

    public String getNewId(String dest, String id, int max) {

        String reslut = id + ",";
        int count = 1;
        String[] items = dest.split(",");
        if (items != null) {
            for (String item : items) {
                if (!"".equals(item) && !item.equals(id)) {
                    reslut += item + ",";
                    count++;
                    if (count == max) {
                        break;
                    }
                }
            }
        }
        return reslut.substring(0, reslut.length() - 1);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        doGet(request, response);
    }
}

 Session技术

Session提供了一种跨多个页面请求或访问网站时识别用户以及存储有关用户信息的方式。Servlet 容器使用这个接口来创建一个 HTTP 客户端和 HTTP 服务器之间的 session 会话。会话持续一个指定的时间段,跨多个连接或页面请求。
Session是J2EE中四大域对象之一,作用范围为整个会话。
可以通过调用 HttpServletRequest 的公共方法 getSession() 来获取 HttpSession 对象,如下所示:
  HttpSession session = request.getSession();


生命周期

在第一次调用reqeust.getSession()方法的时候,服务器会检查是已经有对应的session,如果没有就在内存中创建一个session并返回。
当一段时间内session没有被使用,一般为30分钟(此值可以在web.xml中配置<session-config>来配置,也可以使用TomcatManager进行配置),则服务器会销毁该session。
当服务器强行关闭时,没有到期的session也会跟着销毁。
如果调用session提供的invalidate(),可以立即销毁session。

Session工作原理

在服务器第一次调用request.getSession()方法的时候,request.getSession()方法会检查请求中有没有JSESSIONID cookie,如果有拿出他的值找到对应的session为他服务.
如果没有则检查请求的URL后有没有以参数的形式带着JSESSIONID过来,如果有则找到对应的Session为浏览器服务器。
如果还找不到则认为这个浏览器没有对应的Session,创建一个Session然后再在响应中添加JSESSIONID cookie,值就是这个Session 的id。
同一台电脑内的不同浏览器使用同一个session:JSESSIONID这个cookie默认是保存在浏览器内存中的,可以自己创建一个同名同path的Cookie,并设置maxage值,使其被保存在硬盘中,从而实现统一电脑中不同浏览器公用一个JSESSIONID从而使用同一个session。如果浏览器设置为禁用Cookie,则前面的方法不能使用需要使用URL重写,将Session id保存到URL中。

URL重写

  将URL进行重写拼接上JSESSIONID的过程就叫做URL重写。

URL重写步骤:
首先调用request.getSession()确保Session 存在。
然后使用response.encodeURL()方法进行转换,转换后的URL中就包含了jsessionid参数。
    String url = request.getContextPath() + "/servlet/SessionDetail?prod=Java编程思想";
    url = response.encodeURL(url);
注意
  request.getSession() 在URL重写之前一定要先创建出Session,才有Session id,才能进行重写
  response.encodeURL() 一般的地址都用这个方法重写
  response.encodeRedirectURL() 如果地址是用来进行重定向的则使用这个方法
  url重写的方法一旦发现浏览器带回了任意cookie信息,则认为客户端没有禁用cookie,就不会再进行重写操作

package com.john.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionBuy extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        HttpSession session = request.getSession();
        String prod = (String) session.getAttribute("prod");
        if (prod == null) {
            out.println("还没有选择任何商品。");
        } else {
            out.println("购买 " + prod + " 成功!");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
package com.john.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionDetail extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();

        String prod = request.getParameter("prod");
        out.println("你选择了:" + prod);

        HttpSession session = request.getSession();
        session.setAttribute("prod", prod);
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setPath(request.getContextPath());
        cookie.setMaxAge(60 * 30);
        response.addCookie(cookie);
        
        String url = request.getContextPath() + "/servlet/SessionDetail?prod=Java编程思想";
        url = response.encodeURL(url);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path
            + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>SessionJsp test</title>

</head>

<body>
    <a href="<%=request.getContextPath()%>/servlet/SessionDetail?prod=Java编程思想">Java编程思想</a>
    <br>
    <a href="<%=request.getContextPath()%>/servlet/SessionDetail?prod=设计模式">设计模式</a>
    <br>
    <hr>
    <a href="<%=request.getContextPath()%>/servlet/SessionBuy">购买</a>
    <br>
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path
            + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>SessionJsp 2 test</title>

</head>

<body>
    <%
        request.getSession();
        String url1 = request.getContextPath() + "/servlet/SessionDetail?prod=Java编程思想";
        url1 = response.encodeURL(url1);

        String url2 = request.getContextPath() + "/servlet/SessionDetail?prod=设计模式";
        url2 = response.encodeURL(url2);

        String url3 = request.getContextPath() + "/servlet/SessionBuy";
        url3 = response.encodeURL(url3);
    %>

    <a href="<%=url1%>">Java编程思想</a>
    <br>
    <a href="<%=url2%>">设计模式</a>
    <br>
    <hr>
    <a href="<%=url3%>">购买</a>
    <br>
</body>
</html>

Cookie 和 Session的优缺点比较

Cookie是客户端技术

数据保存在客户端,这个信息可以保存很长时间
数据随时有可能被清空,所以cookie保存的数据是不太靠谱的
数据被保存在了客户端,如果将一些敏感信息比如用户名密码等信息存在cookie中,有安全问题

session是服务器端技术

数据保存在服务区端,相对来说比较稳定和安全
占用服务器内存,所以一般存活的时间不会太长,超过超时时间就会被销毁.需要根据服务器的压力和session 的使用情况合理设置session的超时时间,既能保证session的存活时间够用,同时不用的session可以及时销毁减少对服务器内存的占用.

原文地址:https://www.cnblogs.com/diysoul/p/5572705.html