目录
[8.HTTP Cookie](#8.HTTP Cookie)
[9.HTTP Session](#9.HTTP Session)
[8&&9 总结](#8&&9 总结)
1.HTTP协议
虽然我们说,应用层协议是我们自已定的.但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用。HTTP(超文本传输协议)就是其中之一。
在互联网世界中,HTTP(HyperTextTransferProtocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如HTML文档)。
HTTP协议是客户端与服务器之间通信的基础。客户端通过HTTP协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP协议是一个无连接、无状态的协议(底层是tcp,tcp是连接的,但是http不在意,http只管使用文件描述符),即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息。
2.URL
平时我们俗称的"网址"其实就是说的URL,即统一 资源 定位 符
http://user:pass@www.example.jp:80/dir/index.htm?uid=1#ch1
我们从服务器获取的,都是资源。这些资源在哪里,在服务器上,在linux服务器上,而linux一切皆文件,这些资源也是一个个文件,问题来了,怎么找到这些文件呢,文件必然有路径,但路径只能标识在一个服务器里的唯一性,但是在全网这么多服务器里,怎么标识自己呢?那就是先标识全网唯一一个服务器,再标识这个服务器里的一个进程,最后再标识文件的路径,即ip+port +文件路径,即可定位全网唯一一个资源。
而上面的域名或者说服务器地址,在实际路由访问的时候会被dns解析成具体的ip地址。而前面的http就是说明用http协议来向指定的一台服务器的指定的一个进程中发送获取 文件路径标识的唯一文件资源并在浏览器解析 的请求(如果单纯下文件,是ftp协议,上传文件又是另一种协议,比如上传云盘的时候)。
url里的/是什么,不就是linux文件路径的分隔符吗。
注意,http对信息传输基本不加密,之所以我们现在访问的url都是https协议,是因为https协议对数据传输是有加密的,但2者在使用上区别不大,我这次先讲http,https后面再专门写篇文章。
另外,我们还会发现,实际的url我们看不到port,这是因为商业化的网站,协议对应的端口号都是固定的,即知名端口号,比如http就是80,https就是443,浏览器会默认根据协议传递固定的端口号,我们填url的时候可以主动填,也可以省略,为了方便,现在广泛使用的url基本都是不带显示的port的,都是靠发起请求的浏览器或app自动拼接。
图中的登录信息,现在基本不会用了,因为很不安全,这只是标准的http的url格式罢了。
最后的片段标识符,现在基本也不用了,主要用例就是轮播图,我们进入网页的时候,其实把轮播图都下过来了,然后靠定时任务,通过更改片段标识符来实现轮播。
图中,是访问了bing搜索引擎国内域名的search服务,?后面跟的,就是请求服务的时候要传给服务器的参数,参数都是键值对,这些键值对之间用&隔开。比如q=acg%2B,%2B的解释看下面。这里就是一个键值对,q键的键值是acg%2B,其实很好理解,q很明显就是question,像百度的就是wd=xxxx,就是word的意思。
3.urlencode和urldecode
像/ ?等这样的字符,已经被url当做特殊意义理解了.因此这些字符不能随意出现.
比如,某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义。
转义的规则如下 :将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
例如:
'+'被转义成了 "%2B"
urldecode就是urlencode的逆过程;
UrlEncode编码/UrlDecode解码 - 站长工具
另外,我们会发现,我们搜中文,把url复制下来,我们也会发现汉字被被转义,但是英文没有被转义,是因为这些协议和计算机本身就是外国人先发明的,英语又只需要一个ascll码表(把数字和字母映射起来,其他编码,比如utf8也是一样)就够了,ascll只需要100多个数字就能把所有字母和常见字符表示出来,这就导致,英文是可以直接通过高亮像素点的方式显示出来,而汉字,国内的浏览器或者支持汉字编码的浏览器也会把汉字高亮像素点的方式显示出来。
但是当我们把url复制下来,输入到txt里,会发现实际上还是被转义了(通俗点就是字母在大多数情况下不会以转义方式显现,内在还是转义,但显现是直接以字母方式出现,而汉字就要看情况了,有直接显现也有转义)。最后,不管是字母还是汉字,本身依旧是被编码表映射的,实际网络传输依旧是数字,更准确的说是01二进制。
我上面说的显现是这种,就是浏览器把汉字的转义码解释成了汉字显示出来(显示本质上就是高亮屏幕像素点)
而实际你把这段复制在不支持解释的环境下,核心依旧是转义码。
cpphttps://cn.bing.com/search?mkt=zh-cn&pc=LNVB&FORM=LNOVCH&q=%E6%80%8E%E4%B9%88%E7%9C%8B%E7%94%B5%E8%84%91%E5%89%AA%E5%88%87%E6%9D%BF服务端收到这些请求后肯定也要做解码,比如把转义码对应成具体的汉字等等,这种解码工作,是urldecode,我们基本不用自己写,网上这个代码现成的一堆,copy过来,测试没问题就可以用了。
4.HTTP协议请求与响应格式
我下面4.3自己写了个测试http请求和响应的,可以看看。
我这边主要是基于http1.0版本来理解http,常用的是1.1,像我下面4.3用浏览器发送的http请求,也是1.1版本,而http本身也有2.0,3.0什么的。其实区别不算特别大。
4.1请求
htmlPOST https://api.example.com/user/login HTTP/1.1 Host: api.example.com Connection: keep-alive Content-Length: 47 Cache-Control: max-age=0 Origin: https://api.example.com Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8 Referer: https://api.example.com/login Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: session_id=abc123def456; csrf_token=xyz789; theme=dark; user_prefs=lang=zh_cn username=test_user&password=test_123456&remember_me=true首行:[方法]+[url] +[版本]
这里的版本是客户端的版本
Header :请求的属性,冒号分割的键值对;每组属性之间使用\r\n分隔;遇到空行表示Header部分结束
Body:空行后面的内容都是Body。Body允许为空字符串.如果Body存在,则在Header中会有一个Content-Length属性来标识Body的长度(多少字节);
而协议必然要解决报头和有效载荷的问题,Header和首行就是报头,Body的部分是有效载荷。\r\n既是属性间的分隔符,也是报头和有效载荷间的分隔符,注意空行也是\r\n。
4.2响应
htmlHTTP/1.1 200 OK Server: Nginx/1.18.0 Content-Type: text/html;charset=UTF-8 Content-Language: en-US Cache-Control: max-age=3600 Content-Length: 1274 Date: Thu, 22 Jan 2026 07:30:00 GMT <!DOCTYPE html> <html> <head> <title>示例大学学生服务系统</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="shortcut icon" href="/assets/images/favicon.ico"> <link href="/assets/css/bootstrap.min.css" rel="stylesheet" media="screen" /> <link href="/assets/css/main.css" rel="stylesheet" media="screen" /> <link href="/assets/css/font-awesome.min.css" rel="stylesheet" media="screen" /> <script type="text/javascript" src="/assets/js/jquery-3.6.0.min.js"></script> <script type="text/javascript" src="/assets/js/bootstrap.bundle.min.js"></script> <script type="text/javascript" src="/assets/js/custom.js"></script><!--custom scripts--> <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"> </head> <body> <div class="container"> <header> <h1>示例大学学生服务系统</h1> </header> <nav> <ul> <li><a href="/">首页</a></li> <li><a href="/services">学生服务</a></li> <li><a href="/academic">学术资源</a></li> <li><a href="/career">就业信息</a></li> <li><a href="/login">登录</a></li> </ul> </nav> <main> <section class="welcome"> <h2>欢迎访问学生服务系统</h2> <p>这里是示例大学官方学生服务平台,提供各类学生服务和资源。</p> </section> </main> <footer> <p>© 2026 示例大学学生服务部 版权所有</p> </footer> </div> </body> </html>首行:[版本号]+[状态码]+[状态码解释]
状态码其实就是我们平时访问浏览器发现返回404,520等等,比如404是not found。比如200就是正常状态,OK就是解释下这个状态,像我之前写的网络计算器的code也是可以通过在协议类里增加一个string 对象来解释code的意思。
版本是指服务端的http版本。
Header :请求的属性,冒号分割的键值对;每组属性之间使用\r\n分隔;遇到空行表示Header部分结束
**Body:**空行后面的内容都是Body.Body允许为空字符串.如果Body存在,则在Header中会有一个Content-Length属性来标识Body的长度;如果服务器返回了一个html页面,那么html页面内容就是在body中.
另外响应的协议格式,其实也是空行前都是报头,空行后是有效载荷,也就是正文。
我们可以用telnet在linux上发送http请求,并获取应答
根据这个内容,其实也可以发现,序列化和反序列化就是依靠\r\n把整个字符串分隔开,然后一个个处理即可,这也是为什么说http尽量不依靠第三方库来序列化和反序列化,因为希望我们自己来手写。另外,urI严格意义上,其实是从域名后面的第一个'/'开始的,这第一个'/',是web的根目录,但不一定是linux的根目录,原则上可以是linux的任何目录。
关于版本的问题,稍微大型的软件,服务端必然是会收到旧版本和新版本客户端的请求,这是非常正常的,一方面是软件不会一次性所有人都推送更新,而是一部分一部分的推送,另一方面就是也不是每个人都愿意更新的。所以版本号的存在就是让服务端可以根据客户端的版本反馈正确的应答。
4.3自行编写http服务器,查看请求和响应
顾名思义,主要是为了看下请求和响应的实际格式,关于tcp粘报问题,我就不处理了。
注意,http是现成的协议,我们测试的话,不需要自己搓客户端,有现成的客户端即浏览器,所以我只写了服务端,另外http本身就是比较偏底层的协议,它尽量不依赖任何第三方库,像我之前写的网络计算器,就是依赖了jsoncpp库。
因为我们绑的不是http固定的80端口,外加浏览器默认是http,所以我们只要浏览器输入ip:port即可向服务端发送请求。
如图所示
小发现,当我们只是ip+端口的时候,我们浏览器实际上是发送了2次请求,一个是url是/,一个是/favicon.ico,后者是访问图标,我们会发现几乎所有网站都有自己的图标。
可以发现,我们自己的网页此时没有图标,所以是默认的这个网状球,其他网页都有自己的图标。
当我们访问只写了ip+端口的时候,不考虑图标的问题,默认就是/,否则就是一段linux路径。一般当不指定路径的时候,我们是把/的应答设置成返回默认首页,比如index.html,index.htm。而虽然url是/,但实际上我们不可能把linux的根目录开放给用户,所以,我们默认把/当成是web服务器的根目录,而web服务器的根目录,则由我们自己设置。而设置了根目录,/返回默认首页,其实就是加个判断的问题罢了。
以上页面,是我让AI写的网页html,我主要是写了后端的请求处理流程。
另外,虽然我没写,但是先说,我们平时进行的网页页面的跳转,比如从个人主页到网站首页,跳转的过程,在html里可以是一个<a href="/2.html">,而这个语句的本质,就是发起了一次,访问web根目录下2.html的请求。
因此,网站在我们的眼里,其实是一堆特定目录和文件构成的目录结构。
而我的代码,其实负责就是维护一个web服务器,当有http请求到来时,根据请求,返回相应的应答给client,应答里的正文是请求中所制定的资源路径的内容,可以说就是后端,是IO程序。
获取一张完整的网页,浏览器的流程一般是:获取html -> 渲染解析html -> <img>、<a>等标签 -> 浏览器会发起二次或多次请求 -> 完成获取完整网页 ->最后的结果就是完整的网页了。
5.HTTP的方法
下图为AI
最常见的就是get和post
5.1.GET方法
用途:用于请求URL指定的资源。
示例:GET /index.html HTTP/1.1
特性:指定资源经服务器端解析后返回响应内容。
Get可以请求,也可以传输数据
我们可以发现,form表单会把填写的内容,以name=value的方式提交,多个参数用&隔开,并且?之后是参数,前面是真正访问的url。总结一下,就是get会以url的方式,提交参数给服务器。
注意,action的目标不一定是一个网页,他也可以是一个服务,究竟取什么看我们,比如/login,而我们要做到的是,在后端写if判断,在if ture的作用域里面把整个url分成2部分,然后根据需要把登录需要的参数与数据库进行比对等等。
这种传参方式,因为是放在url里的,所以参数不能太大。
不过,form标签的默认方法就是GET
5.2POST方法
用途 :用于传输实体的主体,通常用于提交表单数据。
示例 : POST /submit.cgi HTTP/1.1
特性 :可以发送大量的数据给服务器,并且数据包含在请求体中。
别管日志部分,我请求最后没有加换行。
可以发现,post请求,就是将参数放在了请求的正文部分。而且这次是点了提交之后,因为我的action目标就是/index.html即我的首页,所以我会马上跳到首页,而不是像get一样,因为参数也放进url了,导致即使前面url是/index.html,但是仍然反馈是404,找不到资源。
2种参数上传的方法不一样,所以提取参数的方法也不一样。post因为把参数放在了正文里,可以传递更多更大的数据。
另外,这2种方法,都是可以被抓包抓到的,也就是说参数都是明文的,只是对于用户来说,post的参数不放在url里,所以会更加的私密。
所以http协议下,post和get都不安全,因为虽然用户看不到post的参数,但是通过抓包工具是可以看到的,http的数据传输中,数据是不加密的,自然就称不上安全。
这也是为什么要有https,因为https对数据进行了加密,后面我会再写一篇关于https的。
5.3PUT方法
用途 :用于传输文件,将请求报文主体中的文件保存到请求URL指定的位置。
示例 :PUT /example.html HTTP/1.1
特性:不太常用,但在某些情况下,如RESTfulAPI中,用于更新资源。
5.4HEAD方法
用途 :与GET方法类似,但不返回报文主体部分,仅返回响应头。
示例 :HEAD /index.html HTTP/1.1
特性:用于确认URL的有效性及资源更新的日期时间等。
5.5DELETE方法
用途 :用于删除文件,是PUT的相反方法。
示例 :DELETE /example.html HTTP/1.1
特性:按请求URL删除指定的资源。
5.6OPTIONS方法
用途 :用于查询针对请求URL指定的资源支持的方法。
示例 :OPTIONS * HTTP/1.1
特性:返回允许的方法,如GET、POST等。(应答中会有allow字段)
6.HTTP的状态码
类别 原因短语 1XX Informational(信息性状态码) 接收的请求正在处理 2XX Success(成功状态码) 请求正常处理完毕 3XX Redirection(重定向状态码) 需要进行附加操作以完成请求 4XX ClientError(客户端错误状态码) 服务器无法处理请求 5XX ServerError(服务器错误状态码) 服务器处理请求出错 最常见的状态码,比如200(OK),404(NotFound),403(Forbidden),302(Redirect,重定向),504(BadGateway)
状态码 含义 应用样例 100 Continue 上传大文件时,服务器告诉客户端可以继续上传 200 OK 访问网站首页,服务器返回网页内容 201 Created 发布新文章,服务器返回文章创建成功的信息 204 No Content 删除文章后,服务器返回"无内容"表示操作成功 301 Moved Permanently 网站换域名后,自动跳转到新域名;搜索引擎更新网站链接时使用 302 Found或See Other 用户登录成功后,重定向到用户首页 304 Not Modified 浏览器缓存机制,对未修改的资源返回304状态码 400 Bad Request 填写表单时,格式不正确导致提交失败 401 Unauthorized 访问需要登录的页面时,未登录或认证失败 403 Forbidden 尝试访问你没有权限查看的页面 404 Not Found 访问不存在的网页链接 500 Internal Server Error 服务器崩溃或数据库错误导致页面无法加载 502 Bad Gateway 使用代理服务器时,代理服务器无法从上游服务器获取有效响应 503 Service Unavailable 服务器维护或过载,暂时无法处理请求 客户端错误,比如404,本质上,是客户端主动访问了本就不存在的资源,这并不是服务器的错,因为网站本身就设计好了各种请求相应的按钮、标签等等,服务器只负责处理这些请求,其他请求本就没有定义,因此是客户端的错误。其他4开头的也是类似。
但注意,状态码只是建议,但不一定,人家非把5开头的错误,以4开头的错误返回给你,那你也没辙。
6.1重定向
以下是仅包含重定向相关状态码的表格
状态码 含义 是否为临时重定向 应用样例 301 Moved Permanently 否 (永久重定向) 网站换域名后,自动跳转到新域名;搜索引擎更新网站链接时使用 302 Found或SeeOther 是 (临时重定向) 用户登录成功后,重定向到用户首页 307 Temporary Redirect 是 (临时重定向) 临时重定向资源到新的位置 (较少使用) 308 Permanent Redirect 否 (永久重定向) 永久重定向资源到新的位置 (较少使用) HTTP状态码301(永久重定向)和302(临时重定向)都依赖Location选项。
6.1.1HTTP状态码301(永久重定向)
当服务器返回HTTP301状态码时,表示请求的资源已经被永久移动到新的位置。
在这种情况下,服务器会在响应中添加一个Location头部,用于指定资源的新位置。这个Location头部包含了新的URL地址,浏览器会自动重定向到该地址。
例如,在HTTP响应中,可能会看到类似于以下的头部信息:
phpHTTP/1.1 301 Moved Permanently\r\n Location: https://www.new-url.com\r|n什么是搜索引擎更新链接?实际上,我们通过浏览器的搜索引擎搜到的网页,都是搜索引擎自己通过爬虫得到的(各个网站对搜索引擎的爬虫行为基本是表示欢迎的,因为这代表的可能有的收益),搜索引擎自己会建数据库来存取自己爬虫爬到的信息,反馈给用户,就是一条条可以点击的网页标签。当网站本身更新了域名,这时候搜索引擎也必须及时的更新,而搜索引擎怎么知道网站更新了域名呢?就是通过301来通知的。而且为什么很多网站的标题本身就很吸引人呢,因为标题在很多搜索引擎算法里面也是一个排网站先后的权值因素之一。
6.1.2HTTP状态码302(临时重定向)
当服务器返回HTTP302状态码时,表示请求的资源临时被移动到新的位置。
同样地,服务器也会在响应中添加一个Location头部来指定资源的新位置。浏览器会暂时使用新的URL进行后续的请求,但不会缓存这个重定向。
例如,在HTTP响应中,可能会看到类似于以下的头部信息:
phpHTTP/1.1 302 Found\r\n Location: https://www.new-url.com\r\n这是我利用302状态码加location,把我自己写的这个http服务器,变成了访问之后自动跳转到我博客主页。
主要是舍弃了正文、正文长度,指定了状态码为302,及其描述,另外增加了location字段,url就是我博客主页的。
另外,301在这里测试的话,效果也是一样的。
而且,我们也可以这样来隔开正常访问和重定向访问
除了跨站,站内各个资源也可以通过这种方式来人为的跳转。
无论是HTTP301还是HTTP302重定向,都需要依赖Location选项来指定资源的新位置。这个Location选项是一个标准的HTTP响应头部,用于告诉浏览器应该将请求重定向到哪个新的URL地址。
7.HTTP常见Header
**Content-Type:**数据类型(text/html等)
(注意,现在浏览器很强大,可以自己识别,但是万一客户端不是浏览器而是其他呢,所以还是要注意这个类型),因此http服务器内部,要根据目标要访问的资源的文件后缀,区分清楚文件类型,通过这个属性,告诉浏览器,response正文的类型!
以下为AI生成,也可以去网上搜,这个很多的。HTTP content-type | 菜鸟教程
我们真正写项目的时候,需要把这些对照关系以配置文件的方式导入服务器。
Content-Length: Body的长度
Host: 客户端告知服务器,所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
**Referer:**当前页面是从哪个页面跳转过来的;这个字段一般也可以用于拦截某些特定域的请求
Location: 搭配3xx状态码使用,告诉客户端接下来要去哪里访问;
**Cookie:**用于在客户端存储少量信息.通常用于实现会话(session)的功能;
7.1connection报头
HTTP中的Connection字段是HTTP报文头的一部分,它主要用于控制和管理客户端与服务器之间的连接状态
7.1.1核心作用
**管理持久连接:**Connection字段还用于管理持久连接(也称为长连接)。持久连接允许客户端和服务器在请求/响应完成后不立即关闭TCP连接,以便在同一个连接上发送多个请求和接收多个响应。
其实所谓的长连接,就是给当有一个新的,未知ip发送来的请求后,建议一个新的会话,这个会话由一个线程维持,内部进行循坏,不断读取请求和处理请求,直到客户端结束,也就是会话结束后,线程再结束。
7.1.2持久连接(长连接)
**HTTP/1.1:**在HTTP/1.1协议中,默认使用持久连接。当客户端和服务器都不明确指定关闭连接时,连接将保持打开状态,以便后续的请求和响应可以复用同一个连接。
**HTTP/1.0:**在HTTP/1.0协议中,默认连接是非持久的。如果希望在HTTP/1.0上实现持久连接,需要在请求头中显式设置 Connection: keep-alive。
7.1.3语法格式
Connection: keep-alive 表示希望保持连接以复用TcP连接。
Connection: close表示请求/响应完成后,应该关闭TCP连接。
7.2常见header
字段名 含义 样例 Accept 客户端可接受的响应内容类型 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding 客户端支持的数据压缩格式 Accept-Encoding: gzip, deflate, br Accept-Language 客户端可接受的语言类型 Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Host 请求的主机名和端口号 Host: www.example.com:8080 User-Agent 客户端的软件环境信息 User-Agent: Mozilla/5.0 (Windows NT 10.0;Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Cookie 客户端发送给服务器的HTTP cookie信息 Cookie: session_id=abcdefg12345; user_id=123 Referer 请求的来源URL Referer:http: //www.example.com/previous_page.html Content-Type 实体主体的媒体类型 Content-Type: application/x-www-form-urlencoded (对于表单提交)或 Content-Type:application/json (对于JSON数据) Content-Length 实体主体的字节大小 Content-Length: 150 Authorization 认证信息,如用户名和密码 Authorization: BasicQWxhzGRpbjpvcGVuIHNlc2FtZQ==(Base64编码后的用户名:密码) Cache-Control 缓存控制指令 请求时:Cache-Control:no-cache 或 Cache-Control: max-age=3600 ; 响应时:Cache-Control: public, max-age=3600 Connection 请求完后是关闭还是保持连接 Connection: keep-alive 或 Connection: close Date 请求或响应的日期和时间 Date: Wed, 21 0ct 2023 07:28:00 GMT Location 重定向的目标URL(与3xx状态码配合使用) Location:http://www.example.com/new_location.html (与302状态码配合使用) Server 服务器类型 Server: Apache/2.4.41 (Unix) Last-Modified 资源的最后修改时间 Last-Modified: Wed, 21 0ct 2023 07:20:00 GMT ETag 资源的唯一标识符,用于缓存 ETag: "3f80f-1b6-5f4e2512a4100" Expires 响应过期的日期和时间 Expires: Wed, 21 0ct 2023 08:28:00 GMT
8.HTTP Cookie
8.1基本介绍
8.1.1定义
HTTPCookie(也称为WebCookie、浏览器Cookie或简称Cookie)是服务器发送到用户浏览器并保存在浏览器上的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态、记录用户偏好等。
8.1.2工作原理
当用户第一次访问网站时,服务器会在响应的HTTP头中设置Set-Cookie字段,用于发送Cookie到用户的浏览器。
浏览器在接收到Cookie后,会将其保存在本地(通常是按照域名进行存储)
在之后的请求中,浏览器会自动在HTTP请求头中携带Cookie字段,将之前保存的Cookie信息发送给服务器。
8.1.3分类
会话 Cookie(Session Cookie) :在浏览器关闭时失效。
持久Cookie(PersistentCookie) :带有明确的过期日期或持续时间,可以跨多个浏览器会话存在。
如果cookie 是一个持久性的cookie,那么它其实就是浏览器相关的,特定目录下的一个
文件。但直接查看这些文件可能会看到乱码或无法读取的内容,因为cookie文件通常以二进
制或sqlite格式存储。一般我们查看,直接在浏览器对应的选项中直接查看即可。如图:
8.1.4安全&&用途
由于Cookie是存储在客户端的,因此存在被篡改或窃取的风险。
用户认证和会话管理(最重要)跟踪用户行为
缓存用户偏好等
8.2认识cookie
HTTP存在一个报头选项:Set-Cookie,可以用来进行给浏览器设置Cookie 值。
在HTTP响应头中添加,客户端(如浏览器)获取并自行设置并保存Cookie。
8.2.1基本格式
Set-Cookie: <name>=<value>
其中<name>是Cookie 的名称,<value>是Cookie 的值。
htmlSet-Cookie: username=peter; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/; domain=.example.com; secure; HttpOnly expires=<date>:设置Cookie 的过期日期/时间。如果未指定此属性,则 Cookie默认为会话Cookie,即当浏览器关闭时过期。 path=<some_path>:限制Cookie 发送到服务器的哪些路径。默认为设置它的路 径。 domain=<domain_name>:指定哪些主机可以接受该Cookie。默认为设置它的 主机。 Secure:仅当使用HTTPS协议时才发送Cookie。这有助于防止Cookie在不安 全的HTTP连接中被截获。 HttpOnly:标记Cookie为HttpOnly,意味着该Cookie不能被客户端脚本(如 JavaScript)访问。这有助于防止跨站脚本攻击(XSS)。时间格式必须遵守RFC1123标准,具体格式样例::Tue, 01 Jan 2030 12:34:56 GMT或者UTC(推荐)。
Tue:星期二(星期几的缩写)
,:逗号分隔符
01:日期 (两位数表示)
Jan:一月(月份的缩写)
2030:年份 (四位数)
12:34:56:时间(小时、分钟、秒)
GMT:格林威治标准时间(时区缩写)
关于时区GMT和UTC,可以自行AI,我这里就不水字数了。只说一句,UTC已经成为了全球性的标准时间,而GMT则更多被用作历史和地理上的参考。
属性 值 描述 username peter 这是Cookie的名称和值,标识用户名为"peter"。 expires Thu, 18 Dec 2024 12:00:00 UTC 指定Cookie的过期时间。在这个例子中,Cookie将在2024年12月18日12:00:00UTC后过期。 path / 定义Cookie的作用范围。这里设置为根路径/,意味着Cookie对.example.com域名下的所有路径都可用。 domain .example.com 指定哪些域名可以接收这个Cookie。点前缀(.)表示包括所有子域名。 secure secure 指示Cookie只能通过HTTPS协议发送,不能通过HTTP协议发送,增加安全性。 Http Only Http Only 阻止客户端脚本(如JavaScript)访问此Cookie,有助于防止跨站脚本攻击(XSS)。
8.2.2注意事项&&生命周期、安全性
每个Cookie 属性都以分号(;)和空格( )分隔。
名称和值之间使用等号(=)分隔。
如果Cookie的名称或值包含特殊字符(如空格、分号、逗号等),则需要进行URL编码。
如果设置了expires属性,则Cookie将在指定的日期/时间后过期。如果没有设置expires属性,则Cookie默认为会话Cookie,即当浏览器关闭时过期。
使用secure标志可以确保Cookie仅在HTTPS连接上发送,从而提高安全性。使用Http Only标志可以防止客户端脚本(如JavaScript)访问Cookie,从而防止XSS攻
击。
通过合理设置Set-Cookie的格式和属性,可以确保Cookie的安全性、有效性和可访问性,从而满足Web应用程序的需求。
8.2.3测试cookie
cookie写入到浏览器
注意,多个自定义的cookie属性,必须以多条set-cookie的形式放入应答中。
自动提交(刷新浏览器,刚刚写入的cookie会自动被提交给服务器端)
写入过期时间
测试路径path可以发现,只有url是/login的时候,才会把cookie也一起加入请求头中。
8.2.4单独使用Cookie,有什么问题?
我们写入的是测试数据,如果写入的是用户的私密数据呢?比如,用户名密码,浏览痕迹等。
本质问题在于这些用户私密数据在浏览器(用户端)保存,非常容易被人盗取,更重要的是,除了被盗取,还有就是用户私密数据也就泄漏了。
9.HTTP Session
9.1基本介绍
9.1.1定义&&工作原理
HTTP Session是服务器用来跟踪用户与服务器交互期间用户状态的机制。由于HTTP协议是无状态的(每个请求都是独立的),因此服务器需要通过Session来记住用户的信息。
当用户首次访问网站时,服务器会为用户创建一个唯一的 Session ID,并通过 Cookie 将其发送到客户端。客户端在之后的请求中会携带这个 Session ID,服务器通过 SessionID 来识别用户,从而获取用户的会话信息。
服务器通常会将Session信息存储在内存、数据库或缓存中。
9.1.2安全、时间、用途
与Cookie相似,由于 SessionID是在客户端和服务器之间传递的,因此也存在被窃取的风险。
但是一般虽然 Cookie 被盗取了,但是用户只泄漏了一个 Session ID,私密信息暂时没有被泄露的风险
Session ID便于服务端进行客户端有效性的管理,比如异地登录。
可以通过 HTTPS 和设置合适的 Cookie 属性(如 HttpOnly 和 Secure)来增强安全性。
Session可以设置超时时间,当超过这个时间后,Session会自动失效。服务器也可以主动使Session失效,例如当用户登出时。
用户认证和会话管理存储用户的临时数据 (如购物车内容)
实现分布式系统的会话共享(通过将会话数据存储在共享数据库或缓存中)
9.2测试Session
删除浏览器中指定的服务器上的所有的cookie
谷歌也是类似
访问/login,模拟登录
两个浏览器访问任意的站点资源(一个edge,一个谷歌)
8&&9 总结
HTTP Cookie和Session都是用于在Web应用中跟踪用户状态的机制。Cookie是存储在客户端的,而Session是存储在服务器端的。它们各有优缺点,通常在实际应用中会结合使用,以达到最佳的用户体验和安全性。
session相对cookie是安全一点,因为具体的信息在服务器,而信息有很多种,比如用户的活跃度、登录位置ip或者登录设备。通过对这些信息与实际登录的状态进行比对,是可以查到异常登录(最明显的就是异地登录,基本都要你重新输密码、各种验证),但这只是相对安全的,你要是真能模拟到跟原来用户一样的环境和使用习惯,想要查到也是很难的。









































