Java Web 状态管理(上) Cookie基础

发布时间:2024年01月16日

前言

老早就对浏览器里弹出的是否接受小饼干是啥意思感到好奇了,原来小饼干是cookie这玩意😏😏😏😏
在这里插入图片描述

一、Cookie产生的背景(不重要)

HTTP是一种无状态协议,简单点来说就是一次请求只会对应一次响应,连接关闭后,Web服务器不会保存这次请求响应过程中的任何状态信息,当客户端发送下一个请求时,Web服务器会把这次请求看成一个新的连接,与前次请求无任何关联。
在这里插入图片描述

前面提到了HTTP的无状态,也就是协议对于事务处理没有记忆能力,不保存状态信息意味着如果后续处理仍然需要前面的信息,则必须将之前的信息重传。假如先前信息很多,会导致服务器的应答速度变慢,而且将相同的数据多次传输,这本就是不必要的性能消耗。

因此,产生了两种保持HTTP连接状态的技术Cookie和Session。

二、Cookie简介

Cookie是通过客户端保持状态的一种解决方案,通俗来说,cookie是保存在客户端硬盘上的一个文件,这不是用户手动操作的,而是Web服务器通过客户端上的浏览器的权限来创建与保存文件的。

Cookie文件内的形式是名/值(name/value)的文本信息。

三、Cookie的使用场景引入

常见的应用场景:自动登录网络购物车功能
我们以购物车添加商品为例

添加苹果进入购物车

假设说我在网上购物,看见想买的我就会把它添加进购物车,这个时候我看这个苹果看着不错,我点了一份加入了购物车。
在这里插入图片描述
当我点击加入购物车的按钮后,程序会发生类似于这样的的流程(实际比这复杂的多)
在这里插入图片描述

添加香蕉进入购物车

在这里插入图片描述
正常预期就是,查看购物车时,就会有苹果和香蕉两种商品在里面。

那么假设说没有Cookie

如果说我再将另一个香蕉商品加入购物车,在没有cookie的情况下会是这样的:

我们会发现两次请求两次响应确实都完成了,但HTTP是无状态的啊,也就是说前面我完成了一次添加苹果这种商品请求与响应流程,但第二次我添加香蕉这种商品时的请求响应与第一次是毫无关系的,就像是猴子掰玉米,掰一个掉一个,除非你把每次购物车的更新数据都纳入数据库中,用数据库来返回响应数据(不考虑这些具体情况),否则你只能在购物车里看到一件商品。
在这里插入图片描述

正常有Cookie的情况

在我们第一次点击加入购物车时,发送请求给服务端,服务端负责处理这一请求的Servlet会根据程序员的代码生成键值对格式数据的cookie,我们以一种简单形式如“苹果=1”表示,生成的Cookie会附着在响应头中随响应返回给客户端,客户端的浏览器会解析响应头并在浏览器里的内存中生成cookie。

在这里插入图片描述
在第二次点击加入购物车按钮,将香蕉加入到购物车中时,发送请求时,会将原本在浏览器内存里的cookie附着在请求头中随请求一起发送。服务端中的Servlet会判断请求头中是否有cookie有则解析出对应的cookie【苹果=1】,同时生成请求本来需要生成的cookie【香蕉=1】。再将这两个cookie一起附着到响应头中随响应返回给客户端。浏览器解析响应头,并刷新内存,这时候内存里就会有两个cookie,购物车也就能有两个商品了。以此类推后续过程。
在这里插入图片描述

四、场景简单模拟

创建第一个Servlet类

我们首先创建一个Servlet类,启动服务器后去访问这个Servlet类,使服务器在响应头里附上苹果和香蕉两个简单的cookie

package com.budiu.servlet;

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;
//设置虚拟目录
@WebServlet("/cookieDemo")
public class CookieDemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置页面编码为utf-8
        resp.setContentType("text/html;charset=utf-8");
        Cookie apple_cookie = new Cookie("apple","1" );
        //这是将cookie携带给响应头并保存在客户端的关键API
        resp.addCookie(apple_cookie);
        Cookie banana_cookie = new Cookie("banana","1" );
        resp.addCookie(banana_cookie);
        }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

创建第二个Servlet类来展现cookie

我们通过访问这个Servlet来使服务器在控制台打印这些cookie

package com.budiu.servlet;

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;

@WebServlet("/cookieDemo1")
public class CookieDemoServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从请求头中获取cookie
        Cookie[] cookies=req.getCookies();
        //在控制台中打印出来
        for (int i = 0; i < cookies.length; i++) {
            Cookie cookie=cookies[i];
            System.out.println(cookie);
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

启动服务器并进行抓包展示过程

我们访问第一个Servlet类,并进行抓包后发现,它的响应头里有了set-cookie的字眼
而后面的键值对就是我们创建的cookie,也就是说,现在内存里已经将苹果和香蕉都放进去了。

在这里插入图片描述

我们再访问第二个Servlet来抓包并输出所有cookie,可以在请求标头中看到cookie的字眼,而它的后面就有我们自己设置的苹果和香蕉的cookie,还有一个IDEA自动生成的cookie。
在这里插入图片描述
控制台也输出了这三个cookie对象的地址
在这里插入图片描述

五、Cookie常用方法介绍

1.创建Cookie:

Cookie cookie = new Cookie("key", "value");
response.addCookie(cookie);

2.获取Cookie:

Cookie[] cookies = request.getCookies();
if (cookies != null) {
    for (Cookie cookie : cookies) {
        if (cookie.getName().equals("key")) {
            String username = cookie.getValue();//获取cookie里的value值
            //进行某些业务处理
        }
    }
}

3.删除Cookie:

Cookie cookie = new Cookie("key", "");//用来覆盖原来的键为key的cookie
cookie.setMaxAge(0);//设置为0表示删除cookie  
response.addCookie(cookie);

4.设置Cookie的过期时间:

Cookie cookie = new Cookie("key", "value");
cookie.setMaxAge(60 * 60 * 24 * 365); // 1 年后自动销毁
response.addCookie(cookie);

5.设置Cookie的domain和path:

//创建一个新的 Cookie 对象,名为 "key",值为 "value"  
Cookie cookie = new Cookie("key", "value");  
// 设置此 Cookie 的域名,使其对 example.com 域名有效  
// 这意味着此 Cookie 将被包含在发送到 example.com 的所有请求中  
cookie.setDomain("example.com");  
  
// 设置 Cookie 的路径为 "/",这表示该 Cookie 对整个网站都有效  
// 也就是说,无论用户访问 example.com 的哪个页面,浏览器都会发送此 Cookie  
cookie.setPath("/");  
  
// 将此 Cookie 添加到响应中,使其可以被客户端(通常是浏览器)存储  
// 当客户端之后发送请求到匹配的域名和路径时,它将包含此 Cookie  
response.addCookie(cookie);
 

一般情况下,Cookie只能在同一域名下共享,如果需要在不同域名下共享,需要使用第三方库或者其他技术实现。

六、学习过程中的小疑问

新创建的Cookie 通常放在 HTTP 响应头中,而不是放在请求头中?

当时还不太理解,因为我忘了写Servlet是针对服务器而写的特性,那么请求就是客户端发送服务器的,而响应就是发送给客户端的。前面既然说了,cookie是存储在客户端上的小文件,,这也就好理解为什么cookie是附在响应头里的了,其次,如果 Cookie 放在请求头中,任何中间人攻击者都可以读取或修改这些信息。通过将 Cookie 放在响应头中,客户端可以确保只有服务器能够修改或读取它们。

不过传递的cookie是可以放在请求头里的。

拜拜!
在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_73956489/article/details/133818504
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。