HTTP Cookie与Session

news2024/11/25 7:03:32

目录

一.   引入Cookie

1.1   定义

1.2   工作原理

1.3   分类

二.   认识Cookie

三.   测试Cookie

五.   引入Session

六.   测试Session


这篇博客,我们来看看Cookie与Session,内容干货满满。

一.   引入Cookie

1.1   定义

HTTP Cookie(也称为 Web Cookie、浏览器 Cookie 或简称 Cookie)是服务器发送到 用户浏览器并保存在浏览器上的一小块数据,它会在浏览器之后向同一服务器再次发 起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一 浏览器,如保持用户的登录状态、记录用户偏好等。

1.2   工作原理

当用户第一次访问网站时,服务器会在响应的 HTTP 头中设置 Set-Cookie字段,用于发送 Cookie 到用户的浏览器。

浏览器在接收到 Cookie 后,会将其保存在本地(通常是按照域名进行存储)。

在之后的请求中,浏览器会自动在 HTTP 请求头中携带 Cookie 字段,将之 前保存的 Cookie 信息发送给服务器。

1.3   分类

  • 会话 Cookie(Session Cookie):在浏览器关闭时失效。
  • 持久 Cookie(Persistent Cookie):带有明确的过期日期或持续时间, 可以跨多个浏览器会话存在。

如果 cookie 是一个持久性的 cookie,那么它其实就是浏览器相关的,特定目录下的一个文件。但直接查看这些文件可能会看到乱码或无法读取的内容, 因为 cookie 文件通常以二进制或 sqlite 格式存储。一般我们查看,直接在浏览器对应的选项中直接查看即可。类似下面这样:

此处就是包含的当前站点含有的Cookie和站点数据。

需要注意的是:由于Cookie存储在客户端(如浏览器),是存在泄露的安全问题的。

二.   认识Cookie

Cookie是报头中的一个报头选项,可以用来给客户端设置Cookie值。


基本格式

Set-Cookie: <name>=<value>

 其中 <name> 是 Cookie 的名称, 是 <value> Cookie 的值。也是一个KV结构。


完整的Cookie示例

Set-Cookie: username=peter; expires=Thu, 18 Dec 2024 12:00:00
UTC; path=/; domain=.example.com; secure; HttpOnly

时间格式必须遵守 RFC 1123 标准,具体格式样例:Tue, 01 Jan 2030 12:34:56 GMT 或者 UTC(推荐)

关于时间解释:

  • Tue: 星期二(星期几的缩写)
  • : 逗号分隔符
  • 01: 日期(两位数表示)
  • Jan: 一月(月份的缩写)
  • 2030: 年份(四位数)
  • 12:34:56: 时间(小时、分钟、秒)
  • GMT: 格林威治标准时间(时区缩写)

GMT vs UTC(了解即可): 

GMT(格林威治标准时间)和 UTC(协调世界时)是两个不同的时间标准,但它们在大多数情况下非常接近,常常被混淆。以下是两者的简单解释和区别:

1. GMT(格林威治标准时间):

  • GMT 是格林威治标准时间的缩写,它是以英国伦敦的格林威治区为基准的世界时间标准。
  • GMT 不受夏令时或其他因素的影响,通常用于航海、航空、科学、天文等领域。
  • GMT 的计算方式是基于地球的自转和公转。

2. UTC(协调世界时):

  • UTC 全称为“协调世界时”,是国际电信联盟(ITU)制定和维护的标准时 间。
  • UTC 的计算方式是基于原子钟,而不是地球的自转,因此它比 GMT 更准确。据称,世界上最精确的原子钟 50 亿年才会误差 1 秒。
  • UTC 是现在用的时间标准,多数全球性的网络和软件系统将其作为标准时间。

GMT 和 UTC 的英文全称以及相关信息如下:

  • 1. GMT(格林尼治标准时间)

英文全称:Greenwich Mean Time

GMT 是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义为通过那里的经线。理论上来说,格林尼治标准时间的正午是 指当太阳横穿格林尼治子午线时的时间。

但值得注意的是,地球的自转是有些不规则的,且正在缓慢减速。因此, 格林尼治时间已经不再被作为标准时间使用。

  • 2. UTC(协调世界时)

英文全称:Coordinated Universal Time

UTC 是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量 接近于格林尼治标准时间。

UTC 被广泛使用在计算机网络、航空航天等领域,因为它提供了非常准确和可靠的时间参考。 总结来说,GMT 和 UTC 都曾是或现在是国际上重要的时间标准,但由于地球自转 的不规则性和原子钟的精确性,UTC 已经成为了全球性的标准时间,而 GMT 则更 多被用作历史和地理上的参考。

区别:

• 计算方式:GMT 基于地球的自转和公转,而 UTC 基于原子钟。

• 准确度:由于 UTC 基于原子钟,它比基于地球自转的 GMT 更加精确。


关于其他可选属性的介绍:

  • expires:设置 Cookie 的过期日期/时间。如果未指定此属性,则 Cookie 默认为会话 Cookie,即当浏览器关闭时过期。
  • path:限制 Cookie 发送到服务器的哪些路径。默认为设置它的路径。
  • domain:指定哪些主机可以接受该 Cookie。默认为设置它的主机。了解即可
  • secure:仅当使用 HTTPS 协议时才发送 Cookie。这有助于防止Cookie 在不安全的 HTTP 连接中被截获。了解即可
  • HttpOnly:标记 Cookie 为 HttpOnly,意味着该 Cookie 不能被客户端脚本(如 JavaScript)访问。这有助于防止跨站脚本攻击(XSS)。了解即可

注意事项:

(1)每个 Cookie 属性都以分号(;)和空格( )分隔。

(2)名称和值之间使用等号(=)分隔。

(3)如果 Cookie 的名称或值包含特殊字符(如空格、分号、逗号等),则需要 进行 URL 编码。


Cookie的生命周期:

如果设置了 expires 属性,则 Cookie 将在指定的日期/时间后过期

如果没有设置 expires 属性,则 Cookie 默认为会话 Cookie,即当浏览器关闭时过期

三.   测试Cookie

我们编码来实现Cookie的验证,此处我们采用http形式,所以在前面http的代码上修改,不知道的读者可查看。(点此查看)


测试Cookie写入浏览器:

string ProveCookieWrite()//证明cookie能被写入浏览器
{
    return "Set-Cookie:username=zhangsan;\r\n";
}

 在处理业务函数内部调用测试:

string HandlerHttpRequest(string req)
{
    cout << "-----------------" << endl;
    cout << req << endl;

    string response = "HTTP/1.0 200 OK\r\n";
    response += "\r\n";
    response+=ProveCookieWrite();//测试cookie被写入与自动提交

    response += "<html><body><h1>hello world !</h1></body></html>";
    return response;
}

运行一下看看结果:

 可以看到最后一行确实有Cookie。


测试写入过期时间:

string GetMonthName(int month)
{
    vector<string> months={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    return months[month];
}

std::string GetWeekDayName(int day)
{
    std::vector<std::string> weekdays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    return weekdays[day];
}

string ExpireTimeUseRfc1123(int t)
{
    time_t timeout=time(nullptr)+t;
    struct tm *tm=gmtime(&timeout);//这里不能用localtime,因为localtime是默认带了时区的,gmtime获取的就是UTC统一时间
    char inbuffer[1024];
    snprintf(inbuffer,sizeof(inbuffer),"%s, %02d %s %d %02d:%02d:%02d UTC",
    GetWeekDayName(tm->tm_wday).c_str(),
    tm->tm_mday,
    GetMonthName(tm->tm_mon).c_str(),
    tm->tm_year+1900,
    tm->tm_hour,
    tm->tm_min,
    tm->tm_sec);
    return inbuffer;
}

我们手动定义过期时间。

string ProvePath()
{
    return "Set-Cookie:username=zhangsan; path=/a/b;\r\n";
}

string HandlerHttpRequest(string req)
{
    cout << "-----------------" << endl;
    cout << req << endl;

    string response = "HTTP/1.0 200 OK\r\n";
    response += "\r\n";
    response+=ProveCookieTimeout();//测试过期时间的写入

    response += "<html><body><h1>hello world !</h1>/body></html>";
    return response;
}

运行一下看看效果:

确实是一分钟的过期时间。


测试路径 Path:

string ProvePath()
{
    return "Set-Cookie:username=zhangsan; path=/a/b;\r\n";
}

string HandlerHttpRequest(string req)
{
#ifdef TEST
    cout << "-----------------" << endl;
    cout << req << endl;

    string response = "HTTP/1.0 200 OK\r\n";
    response += "\r\n";
    response+=ProvePath();

    response += "<html><body><h1>hello world !</h1>/body></html>";
    return response;
}

测试效果:

如果提交非/a/b路径下

比如:http://8.137.19.140:8888/a/x

比如:http://8.137.19.140:8888/

比如:http://8.137.19.140:8888/x/y

结果:

提交到/a/b路径下时:


单独使用Cookie存在的问题

前面说过,Cookie是被客户端知晓的,所以如果我们单独使用Cookie,那么很有可能造成数据的泄露。

本质问题就在于这些用户私密数据在浏览器(用户端)保存,非常容易被人盗取,更重要的是,除了被盗取,还有就是用户私密数据也就泄漏了。

这就需要用到我们的Session了。往下继续看看吧。

五.   引入Session


定义

HTTP Session是服务器用来跟踪用户与服务器交互期间用户状态的机制。由于HTTP协议是无状态的(每个请求都是独立的),因此服务器需要通过Session来记住用户的信息


工作原理

当用户首次访问网站时,服务器会为用户创建一个唯一的Session ID,并通过Cookie将其发送到客户端。

客户端在之后的请求中会携带这个Session ID,服务器通过Session ID来识别用户,从而获取用户的会话信息。服务器通常会将Session信息存储在内存、数据库或缓存中。


安全性

与Cookie相似,由于Session ID是在客户端和服务器之间传递的,因此也存在被窃取的风险。

虽然Session ID也有泄露的风险,但是用户只泄漏了一个Session ID,私密信息暂时没有被泄露的风险。Session ID便于服务端进行客户端有效性的管理,比如异地登录。可以通过HTTPS和设置合适的Cookie属性(如HttpOnly和Secure)来增强安全性。


超时与失效

Session可以设置超时时间,当超过这个时间后,Session会自动失效。服务器也可以主动使Session失效,例如当用户退出时。


用途

(1)用户认证和会话管理。

(2)存储用户的临时数据(如购物车内容)。

(3)实现分布式系统的会话共享(通过将会话数据存储在共享数据库或缓存中)。

六.   测试Session

我们封装成两个类,一个类定义Session,另一个类实现Session管理:

#pragma once

#include<iostream>
#include<string>
#include<unordered_map>
#include<ctime>
#include<memory>
#include<unistd.h>


using namespace std;

class Session
{
public:
    Session(const string& username,const string& status)
    :_username(username),_status(status)
    {
        _create_time=time(nullptr);
    }

    ~Session()
    {}
public:
    string _username;
    string _status;
    uint64_t _create_time;
};


using session_ptr=shared_ptr<Session>;

class SessionManager
{
public:
    SessionManager()
    {
        srand(time(nullptr));
    }

    string AddSession(session_ptr s)
    {
        uint32_t randtime=rand()+time(nullptr);//随机数+时间戳,实际有形成sessionid的库,比如boost uuid库,或者其他第三方库等
        string sessionid=to_string(randtime);
        _sessions.insert(make_pair(sessionid,s));
        return sessionid;
    }

    session_ptr GetSession(const string sessionid)
    {
        if(_sessions.find(sessionid)==_sessions.end()) return nullptr;
        return _sessions[sessionid];
    }

    ~SessionManager()
    {}
private:
    unordered_map<string,session_ptr> _sessions;
};

上层处理业务函数:

string HandlerHttpRequest(string req)
{
    auto request = Factory::BuildHttpRequest();
    request->Deserialize(req);
    int contentsize=0;
    string text=ReadFileContent(request->Path(),&contentsize);
    string suffix=request->Suffix();
    int code=302;
    auto response=Factory::BuildHttpResponse();

    static int number=0;
    if(request->Url()=="/login")//用/login path向指定浏览器写入sessionid,并在服务器维护对应的session对象
    {
        string sessionid=request->Session();
        if(sessionid.empty())//说明历史没有登陆过
        {
            string user="user-"+to_string(number++);
            session_ptr s=make_shared<Session>(user,"logined");
            string sessionid=_session_manager->AddSession(s);
            LOG(DEBUG,"%s 被添加,sessionid是:%s\n",user.c_str(),sessionid.c_str());
            response->AddHeader("Set-Cookie: sessionid",sessionid);
        }
    }
    else
    {
        //当浏览器在本站点任何路径中活跃,都会自动提交sessionid,我们就能知道谁活跃了
        string sessionid=request->Session();
        if(!sessionid.empty())
        {
            session_ptr s=_session_manager->GetSession(sessionid);
            //这个地方有坑,一定要判断服务器端session对象是否存在,因为可能测试的时候
            //浏览器还有历史sessionid,但是服务器重启之后,session对象没有了
            if(s!=nullptr)
            {
                LOG(DEBUG,"%s 正在活跃\n",s->_username.c_str());
            }
            else
            {
                LOG(DEBUG,"cookie : %s 已经到期,需要清理\n",sessionid.c_str());
            }
        }
    }

    response->AddStatusLine(code,_code_to_desc[code]);
    //http协议已经给我们规定好了不同文件后缀对应的Content-Type
    
    response->AddHeader("Content-Type",_mime_type[suffix]);
    response->AddHeader("Location","https://www.qq.com/");
    return response->Serialize();
}

访问/login,模拟登录:

总结:

HTTP Cookie 和 Session 都是用于在 Web 应用中跟踪用户状态的机制。Cookie 是存 储在客户端的,而 Session 是存储在服务器端的。它们各有优缺点,通常在实际应用 中会结合使用,以达到最佳的用户体验和安全性。


总结:

好了,到这里今天的知识就讲完了,大家有错误一点要在评论指出,我怕我一人搁这瞎bb,没人告诉我错误就寄了。

祝大家越来越好,不用关注我(疯狂暗示)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2187752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

幂等性及技术解决方案

目录 定义幂等性 为什么需要幂等性幂等性设计注意事项幂等性的范围分布式锁解决幂等性 设计 延伸阅读 定义幂等性 简单地说&#xff0c;我们可以多次执行幂等运算而不改变结果或者使用相同的输入参数中被调用多次&#xff0c;则不具有额外效果的操作&#xff0c;也就是多次执…

使用pytdx获取历史股票行情

使用pytdx获取历史股票行情 先看效果pytdx基础获取历史股票行情将历史数据存入数据库 先看效果 获取从2010年01月01日-2024年09月30日的股票数据 pytdx基础 https://blog.csdn.net/firexiaHouse/article/details/142687052?spm1001.2014.3001.5501 获取历史股票行情 def …

C++11--智能指针

引入 为什么需要智能指针&#xff1f; 在介绍异常时&#xff0c;遇到以下场景&#xff0c;处理异常就会比较棘手&#xff1a; void Func() {int* arr1 new int[10];int* arr2 new int[20];int* arr3 new int[30];// ...delete[] arr1;delete[] arr2;delete[] arr3; }这里…

一文吃透 SpringBoot (从入门到精通)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

15分钟学 Python 第35天 :Python 爬虫入门(一)

Day 35 : Python 爬虫简介 1.1 什么是爬虫&#xff1f; 网页爬虫&#xff08;Web Crawler&#xff09;是自动访问互联网并提取所需信息的程序。爬虫的主要功能是模拟用户通过浏览器访问网页的操作&#xff0c;从而实现对网页内容的批量访问与信息提取。它们广泛应用于数据收集…

【IPv6】IPv6地址格式及地址分类(组播、单播、任播)整理

IPv6地址格式 IPv6 地址从 IPv4 地址的 32 bits 扩展到 128 bits&#xff0c;IPv6 地址的表示、书写方式也从 IPv4 的点分十进制&#xff0c;修改16进制的冒号分割 IPv4 点分格式(.) 192.168.11.11 IPv6 冒号分割(:) 2408:8459:3032:0000:0000:0000:0001:a9fd IPv6 的规范…

平面电磁波的电场能量磁场能量密度相等,注意电场能量公式也没有复数形式(和坡印廷类似)

1、电场能量密度和磁场能量密度相等(实数场算的) 下面是电场能量密度和磁场能量密度的公式&#xff0c;注意这可不是坡印廷定理。且电场能量密度没有复数表达式&#xff0c;即不是把E和D换成复数形式就行的。注意&#xff0c;一个矢量可以转化为复数形式&#xff0c;两个矢量做…

6.4 数据处理架构模式和实践

6.4 数据处理架构模式和实践 目录概述需求&#xff1a; 设计思路实现思路分析1.批处理架构2.实时处理架构3.流处理架构4.微服务架构&#xff08;重点&#xff09;5.数据湖架构6.数据仓库架构 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , s…

Java | Leetcode Java题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; class Solution {public int findMinArrowShots(int[][] points) {if (points.length 0) {return 0;}Arrays.sort(points, new Comparator<int[]>() {public int compare(int[] point1, int[] point2) {if (point1[1] > point2[1…

微软官网列出了 Windows 11 LTSC 2024 中的全部新功能

今天早些时候&#xff0c;微软发布了有关受托管PC的Windows 11 24H2 升级和兼容性的详细信息。 该帖子针对的是负责在各自办公室和组织中处理系统的 IT 系统管理员。与此同时&#xff0c;微软也发布了有关 Windows 11 LTSC 或长期服务渠道的信息。 该公司已于四月早些时候证实…

yolov10+strongsort的目标跟踪实现

此次yolov10deepsort不论是准确率还是稳定性&#xff0c;再次超越了之前的yolodeepsort系列。 yolov10介绍——实时端到端物体检测 YOLOv10 是清华大学研究人员在 UltralyticsPython 清华大学的研究人员在 YOLOv10软件包的基础上&#xff0c;引入了一种新的实时目标检测…

Java 异常一口气讲完!(_ _)。゜zzZ

Java 异常处理 Java面向对象设计 - Java异常处理 异常是在没有定义正常执行路径时在Java程序的执行期间可能出现的条件。 Java通过将执行操作的代码与处理错误的代码分离来处理错误。 当发生异常时&#xff0c;Java会创建一个包含有关异常的所有信息的对象&#xff0c;并将其…

HTML增加文本复制模块(使用户快速复制内容到剪贴板)

增加复制模块主要是为了方便用户快速复制内容到剪贴板&#xff0c;通常在需要提供文本信息可以便捷复制的网页设计或应用程序中常见。以下是为文本内容添加复制按钮的一个简单实现步骤&#xff1a; HTML结构&#xff1a; 在文本旁边添加一个复制按钮&#xff0c;例如 <butto…

蘑菇分类检测数据集 21类蘑菇 8800张 带标注 voc yolo

蘑菇分类检测数据集 21类蘑菇 8800张 带标注 v 蘑菇分类检测数据集 21类蘑菇 8800张 带标注 voc yolo 蘑菇分类检测数据集介绍 数据集名称 蘑菇分类检测数据集 (Mushroom Classification and Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型…

管理方法(12)-- 采购管理

采购人员不是在为公司讨价还价,而是在为顾客讨价还价,我们应该为顾客争取最低的价钱。-----山姆 沃尔顿 沃尔玛的创始人。 1. 采购的定义和原则 5R原则:适时(Right Time)、适质(Right Quality)、适量(Right Quantity)、适价(Right Price)、适地(Right Place)。…

Linux -- 文件系统(文件在磁盘中的存储)

目录 前言&#xff1a; 了解机械磁盘 初始盘片与磁头 盘片是怎么存数据的呢&#xff1f; 详解盘片 如何访问磁盘中的一个扇区呢&#xff1f; -- CHS 定位法 磁盘的逻辑存储 LBA&#xff08;Logical Block Addressing --- 逻辑块寻址&#xff09; 如何将 LBA 地址转换为…

C++ | Leetcode C++题解之第455题分发饼干

题目&#xff1a; 题解&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int m g.size(), n s.size();int count 0;for (int i 0, j 0; i < …

js中各种时间日期格式之间的转换

前言&#xff1a;近几天在做百度地图时,需要转换时间格式并做显示,下面这篇文章主要给大家介绍了关于js中各种时间格式的转换方法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下 &#x1f308;&#x1f308;文章目录 先来认识 js 的时间格式有哪些&#xf…

CSS3旋转、平移、缩放、倾斜

CSS3平移、缩放、倾斜、旋转 前言 下面代码用到了盒子如下&#xff1a; 使用 一、平移translate() 语法&#xff1a;translate(x轴平移距离, y轴平移距离) 使用方式如下&#xff1a; /* x轴平移200px&#xff0c;y轴平移100px */ transform: translate(200px, 100px);二、…

JavaWeb——Vue组件库Element(5/6):案例:组件实现(概述、Form表单、Table表格、Pagination 分页、效果展示、完整代码)

目录 概述 Form表单 Table表格 Pagination 分页 效果展示 完整代码 概述 在刚才制作出来的页面当中&#xff0c;上面项目的名称已制作好&#xff0c;左侧的菜单栏也已配置好。 接下来主要处理的是右侧主展示区域当中的组件编写。 在右侧的主展示区域&#xff0c;主要有…