Java 编程之 Cookie & Session

0x01 前言

  HTTP 为无状态协议,协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传。另一方面,在服务器不需要先前信息时它的应答就较快。客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。

0x02 Cookie

  Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

0x03 Session

  Session,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。

0x04 Java 操作 Cookie

Java 操作 Cookie 步骤

Cookie cookie = new Cookie(String name, String value); // 创建 Cookie 对象 cookie,name 为名,value 为值
resp.addCookie(cookie); // 将 cookie 发送给浏览器,由浏览器保存
Cookie[] cookies = req.getCookies(); // 获取 HTTP request 中 cookie,Cookie 类型的数组形式保存

构建登陆表单

创建用于登陆表单 login.html

<body>
    <form action="/myweb/cookie/login" method="post">
        <p><input type="text" name="username" placeholder="用户名" /></p>
        <p><input name="password" name="password" placeholder="密码" /></p>
        <p><input type="submit" value="提交表单" /></p>
    </form>
</body>

创建浏览器本地 Cookie

  接收 login.html 提交的登陆参数账号和密码,req.getParamter() 方法接收 request 提交的参数并赋值给 String 类型变量 usernamepassword ,创建 Cookie 对象 userCookiepassCookie 并逐一发送给浏览器。

@WebServlet(urlPatterns = "/cookie/login")
public class LoginCookieServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter(); // 页面内容输出对象
        String username = req.getParameter("username"); // 1、捕捉表单提交参数
        String password = req.getParameter("password");
        Cookie userCookie = new Cookie("username", username); // 2、创建 cookie
        Cookie passCookie = new Cookie("password", password);
        resp.addCookie(userCookie); // 3、发送 cookie 到客户端
        resp.addCookie(passCookie);
        // TODO 其他操作
    }
}

0x05 服务端获取 Cookie 进行处理

  reqs.getCookies() 获取 Cookie 类型数组 Cookie[] cookies,由cookie.getName() 获取 Cookie 的名称,根据名称进行进一步操作。

@WebServlet(urlPatterns = "/cookie/handler")
public class HandlerCookieServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter(); // 页面内容输出对象
        String username = null;
        String password = null;
        Cookie[] cookies = req.getCookies(); // 1、创建 cookie
        if (cookies != null) { // 2、处理 cookie
            for (Cookie cookie : cookies) {
                String key = cookie.getName();
                if ("username".equals(key)) {
                    username = cookie.getValue();
                }
                if ("password".equals(key)) {
                    password = cookie.getValue();
                }
            }
        }
        // TODO 进行其他操作
    }
}

0x06 Java 操作 Session

Java 操作 Session 步骤:

HttpSession session = req.getSession(boolean create); // Session 的创建和获取
session.setAttribute(String name, Object value); // Session 存储数据
String username = session.getAttribute(String name); // Session 获取数据
session.removeAttribute(String name); // Session 删除某个属性值,name 为属性的名称
session.invalidate(); // 销毁 Session 对象
session.setMaxInactiveInterval(60 * 10); // 超过10分钟,销毁 session

  HttpSession session = req.getSession(boolean create);createtrue 时,判断 Session 对象是否存在,存在则返回该 Session 对象,不存在则创建一个新的session。当 createfalse 时,不存在则返回 null

Session的创建、获取和操作

&#8195;&#8195;接收 login.html 提交的登陆参数账号和密码,利用 JavaBean规范创建 User 类,将 `username` 和 `password` 存储在JavaBean规范生成对象中。`req.geetSession()` 创建 Session 对象 `session`,session 以属性名标识session "USER_IN_SESSION" 对应值 `user`。
@WebServlet("/session/login")
public class LoginSessionServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = new User(username, password);
        HttpSession session = req.getSession(); // 1、创建Session
        session.setAttribute("USER_IN_SESSION", user); // 2、创建Session对象
        session.removeAttribute("USER_IN_SESSION"); // 3、删除指定session属性
        session.invalidate(); // 4、销毁session
        session.setMaxInactiveInterval(60 * 10); // 5、超过10分钟无操作则销毁session
        // TODO 进行其他操作
    }
}

Session 获取具体操作

  req.getSession() 创建和获取 session 对象, session.getAttribute("USER_IN_SESSION") 获取强转为 User 类对象 user 调用 getter 获取 usernamepassword

@WebServlet(urlPatterns="/session/handler")
public class DetailSessionServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        HttpSession session = req.getSession();// 1、创建和获取 Session
        User user = (User) session.getAttribute("USER_IN_SESSION"); // 2、处理 Session
        String username = user.getUsername(); // 3、获取对象后调用 getter 取值
        String password = user.getPassword();
    }
}

0x07 Java 操作 Cookie 其他细节

Cookie 原理

  第一次请求时,服务器将 cookie 发送到浏览器,浏览器进行保存,下次请求时,浏览器将 cookie 通过 request 对象发送到服务器。

Cookie 支持中文存储

Cookie userCookie = new Cookie("username", URLEncoder.encode(username, "UTF-8")); // 使用 URLEncoder 编码
username = URLDecoder.decode(cookie.getValue(), "UTF-8"); // 使用 URLDecoder 解码

  String username = req.getParameter("username") 接收 username 应考虑为 GET 提交还是 POST 提交,因为当提交 username 为中文时,注意编码是否为 UTF-8 以规避乱码问题。

会话 Cookie 和持久化 Cookie

  会话 Cookie:生命周期伴随着会话的开始和结束。

  持久化 Cookie:生命周期与会话的开始和结束无关。

cookie.setMaxAge(int expiry);
// expiry > 0 持久化 cookie
// expriy = 0 删除该 cookie
// expriy < 0 会话 cookie,默认值为 -1

Cookie 作用域

  • 不同主机不共享 cookie。

  • 希望不同的二级域名中可以共享 Cookie,那么就要设置 Cookie 的 domain 和 path 了。

  例如:music.baidu.com、map.baidu.com、tieba.baidu.com,它们的域名不同,但百度希望它们之间可以共享 Cookie。

  1. 设置 Cookie 的 path 为 "/" ,例如:cookie.setPath("/") 在整个 baidu.com 中都能传递。

  2. 设置 Cookie 的 domain,例如:cookie.setDomain(".baidu.com"),其中 domain 中没有指定域名前缀!

  3. 在 music.baidu.com 主机中的某个项目中保存了 Cookie。

  4. 在 map.baidu.com 主机中某个项目中获取 Cookie。

0x08 Java 操作 Session 其他细节

命名规则

  一般来说,Session 我习惯命名为“XX_IN_SESSION”例如:USER_IN_SESSION

使用 JavaBean 对象

  若需要把多个数据存放到 Session 中,就得调用 setAttribute() N次。一般的,我们把需要存储的数据,封装成一个对象,然后在存储到 Session 中。例如:把用户的信息,封装到 User 对象 user,再赋给 session。例如:session.setAttribute("USER_IN_SESSION", user);

网络共享 Session

  如果多台服务器之间需要共享 Session ,此时 Session 中的对象,必须实现 java.io.Serializable(序列化)。

URL 带 Session

  当浏览器禁用 Cookie 之后需要手动携带 Session 的 ID,通过链接 url + jessionid 进行手动携带session。例如: String url = http://www.baidu.com/example;jesession=session.session.getId();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容