
文章目录
- [初识网络大门 ------ URL 与 HTTP 协议基础模型](#初识网络大门 —— URL 与 HTTP 协议基础模型)
-
-
- [一、 零基础前提:应用层协议到底是干什么的?](#一、 零基础前提:应用层协议到底是干什么的?)
- [二、 解剖"网址":什么是 URL?](#二、 解剖“网址”:什么是 URL?)
- [三、 避坑细节:字符转义(UrlEncode 与 UrlDecode)](#三、 避坑细节:字符转义(UrlEncode 与 UrlDecode))
- [四、 HTTP 协议的核心骨架模型](#四、 HTTP 协议的核心骨架模型)
- 高频面试题精讲
-
- [面试题 1:平时说的 URL 和 URI 有什么区别?](#面试题 1:平时说的 URL 和 URI 有什么区别?)
- [面试题 2:为什么 URL 中需要 UrlEncode 编码?空格和中文字符是如何被编码的?](#面试题 2:为什么 URL 中需要 UrlEncode 编码?空格和中文字符是如何被编码的?)
-
- [第二篇:庖丁解牛 ------ HTTP 请求与响应报文的底层细节](#第二篇:庖丁解牛 —— HTTP 请求与响应报文的底层细节)
-
-
- [一、 核心比喻:HTTP 报文就像一封"公文信件"](#一、 核心比喻:HTTP 报文就像一封“公文信件”)
- [二、 HTTP 请求报文(Request)的四大结构解剖](#二、 HTTP 请求报文(Request)的四大结构解剖)
-
- [1. 第一行:请求行(Request Line)](#1. 第一行:请求行(Request Line))
- [2. 中间部分:请求报头(Headers)](#2. 中间部分:请求报头(Headers))
- [3. 关键分界线:空行(Blank Line)](#3. 关键分界线:空行(Blank Line))
- [4. 尾部部分:请求正文(Body)](#4. 尾部部分:请求正文(Body))
- [三、 HTTP 响应报文(Response)的四大结构解剖](#三、 HTTP 响应报文(Response)的四大结构解剖)
-
- [1. 第一行:状态行(Status Line)](#1. 第一行:状态行(Status Line))
- [2. 中间部分:响应报头(Headers)](#2. 中间部分:响应报头(Headers))
- [3. 空行(Blank Line)与 响应正文(Body)](#3. 空行(Blank Line)与 响应正文(Body))
- [四、 灵魂拷问:为什么 HTTP 报文必须设计一个"空行"?](#四、 灵魂拷问:为什么 HTTP 报文必须设计一个“空行”?)
- 高频面试题精讲
-
- [面试题 1:请详细描述 HTTP 请求报文和响应报文的结构,它们有哪些相同点与不同点?](#面试题 1:请详细描述 HTTP 请求报文和响应报文的结构,它们有哪些相同点与不同点?)
- [面试题 2:HTTP 是基于文本的协议,面对 TCP 字节流传输,它是如何实现报文定界与拆包的?](#面试题 2:HTTP 是基于文本的协议,面对 TCP 字节流传输,它是如何实现报文定界与拆包的?)
-
- [第三篇:核心请求方法深度剖析:GET 与 POST 的本质差异](#第三篇:核心请求方法深度剖析:GET 与 POST 的本质差异)
-
-
- [GET 方法 = 寄一张"明信片"(用于获取资源)](#GET 方法 = 寄一张“明信片”(用于获取资源))
- [POST 方法 = 寄一个"密封纸箱"(用于提交数据)](#POST 方法 = 寄一个“密封纸箱”(用于提交数据))
- [字符画图解:GET 与 POST 的报文差异](#字符画图解:GET 与 POST 的报文差异)
- [代码级演示:浏览器是如何发起 GET 和 POST 的?](#代码级演示:浏览器是如何发起 GET 和 POST 的?)
- [HTTP 方法家族的其他成员(简单认识)](#HTTP 方法家族的其他成员(简单认识))
- 高频面试题精讲
-
- [第四篇:状态与属性 ------ 状态码全景图与常见 Header](#第四篇:状态与属性 —— 状态码全景图与常见 Header)
-
-
- [一、 核心比喻:状态码与 Header 到底是个啥?](#一、 核心比喻:状态码与 Header 到底是个啥?)
- [二、 状态码全景家族:五大体检结论](#二、 状态码全景家族:五大体检结论)
- [三、 字符画演示:301 / 302 重定向到底是怎么自动跳转的?](#三、 字符画演示:301 / 302 重定向到底是怎么自动跳转的?)
- [四、 核心 Header 快递单属性:大白话拆解](#四、 核心 Header 快递单属性:大白话拆解)
- 高频面试题精讲
-
- [面试题 1:HTTP 状态码 301 与 302 的区别是什么?搜索引擎对此有什么不同反应?](#面试题 1:HTTP 状态码 301 与 302 的区别是什么?搜索引擎对此有什么不同反应?)
- [面试题 2:HTTP 报头中的 `Connection: keep-alive` 是什么意思?与 TCP 的 Keepalive 是一回事吗?](#面试题 2:HTTP 报头中的
Connection: keep-alive是什么意思?与 TCP 的 Keepalive 是一回事吗?)
-
- [第五篇:状态保持加餐 ------ Cookie 与 Session 机制(网站到底是怎么认出你的?)](#第五篇:状态保持加餐 —— Cookie 与 Session 机制(网站到底是怎么认出你的?))
-
-
- [一、 核心比喻:游乐园的"手环门票"与"VIP储物柜"](#一、 核心比喻:游乐园的“手环门票”与“VIP储物柜”)
- [二、 阶段演进:从"纯 Cookie"到"Cookie + Session 配合"](#二、 阶段演进:从“纯 Cookie”到“Cookie + Session 配合”)
-
- [1. 方案一:纯 Cookie 时代(手环上直接写明文信息)](#1. 方案一:纯 Cookie 时代(手环上直接写明文信息))
- [2. 方案二:Cookie + Session 机制(工业界标准解法)](#2. 方案二:Cookie + Session 机制(工业界标准解法))
- [三、 字符画全流程演示:登录与会话保持](#三、 字符画全流程演示:登录与会话保持)
- [四、 Cookie 的核心属性与安全控制](#四、 Cookie 的核心属性与安全控制)
- [五、 C++ 代码模拟演示:轻量级 Session 管理器](#五、 C++ 代码模拟演示:轻量级 Session 管理器)
- 高频面试题精讲
-
- [面试题 1:请详细说一下 Cookie 与 Session 的区别与联系。](#面试题 1:请详细说一下 Cookie 与 Session 的区别与联系。)
- [面试题 2:如果用户的浏览器禁用了 Cookie,Session 还能正常工作吗?如果能,该怎么做?](#面试题 2:如果用户的浏览器禁用了 Cookie,Session 还能正常工作吗?如果能,该怎么做?)
-
- [第六篇:终极安全加餐 ------ HTTPS 协议与密码学破局](#第六篇:终极安全加餐 —— HTTPS 协议与密码学破局)
-
-
- [一、 核心比喻:透明玻璃瓶与"中间人劫持"](#一、 核心比喻:透明玻璃瓶与“中间人劫持”)
- [二、 密码学前置工具箱:两把锁与数字指纹](#二、 密码学前置工具箱:两把锁与数字指纹)
- [三、 方案递进推演:HTTPS 是如何一步步进化出来的?](#三、 方案递进推演:HTTPS 是如何一步步进化出来的?)
-
- [方案 1:只用对称加密(行不通)](#方案 1:只用对称加密(行不通))
- [方案 2:只用非对称加密(行不通)](#方案 2:只用非对称加密(行不通))
- [方案 3:非对称加密 + 对称加密(混合双打,看似完美)](#方案 3:非对称加密 + 对称加密(混合双打,看似完美))
- [四、 灵魂一击:什么是"中间人攻击"?](#四、 灵魂一击:什么是“中间人攻击”?)
- [五、 终极破局:CA 机构与数字证书(方案 5)](#五、 终极破局:CA 机构与数字证书(方案 5))
-
- [1. 什么是数字证书?](#1. 什么是数字证书?)
- [2. 浏览器是如何验真伪的?(防篡改与防调包)](#2. 浏览器是如何验真伪的?(防篡改与防调包))
- [六、 全流程闭环:HTTPS 的"三组密钥"黄金协同](#六、 全流程闭环:HTTPS 的“三组密钥”黄金协同)
- 高频面试题精讲
-
- [面试题 1:HTTPS 建立连接的完整过程(SSL/TLS 握手)是怎样的?](#面试题 1:HTTPS 建立连接的完整过程(SSL/TLS 握手)是怎样的?)
- [面试题 2:为什么数字签名不直接对整个证书明文进行非对称加密,而是要先 Hash 生成摘要再加密?](#面试题 2:为什么数字签名不直接对整个证书明文进行非对称加密,而是要先 Hash 生成摘要再加密?)
- [面试题 3:为什么有了对称加密和非对称加密,HTTPS 依然必须要引入 CA 数字证书?](#面试题 3:为什么有了对称加密和非对称加密,HTTPS 依然必须要引入 CA 数字证书?)
-
- 自问自答
-
-
- [一、 HTTP 协议基础与报文结构](#一、 HTTP 协议基础与报文结构)
- [二、 请求方法与状态码](#二、 请求方法与状态码)
- [三、 Cookie 与 Session](#三、 Cookie 与 Session)
- [四、 HTTPS 与加密基础](#四、 HTTPS 与加密基础)
-
初识网络大门 ------ URL 与 HTTP 协议基础模型
一、 零基础前提:应用层协议到底是干什么的?
想象一下古代两军打仗或者镖局押镖:
- 底层的传输层(TCP/UDP)、网络层(IP)就像是修好的官道马路和负责运货的马车夫。马车夫只负责把一口大箱子从"长安城张三家(IP:Port)"送到"洛阳城李四家(IP:Port)",他根本不管箱子里面装的是绫罗绸缎还是尚方宝剑。
- 而应用层协议 ,就是箱子打开后里面的具体内容规范。比如:双方提前约定好------"第一张纸写收件人,第二张纸写清单,物品用红布包着"。如果双方没约定好,洛阳李四收到一堆乱码字符,就完全不知道张三想干什么。
HTTP(HyperText Transfer Protocol,超文本传输协议),就是全球互联网大佬们共同制定的一套最通用的"开箱验货格式"。客户端(比如你的手机浏览器)和服务器(比如百度的机房服务器)都严格按照这套格式说话,世界各地的网页才能被正确显示。
二、 解剖"网址":什么是 URL?
我们每天在浏览器输入的"网址",学术名称叫做 URL(Uniform Resource Locator,统一资源定位符) 。
顾名思义,它就像是互联网世界的一张精准快递收货地址。
我们通过一个极其经典的完整 URL 来把它拆解得明明白白:
bash
http://user:pass@www.example.com:80/dir/index.html?uid=1&name=cpp#ch1
bash
+--------+-----------+-----------------+------+----------------+-------------------+-----+
| 协议名 | 登录认证 | 服务器地址 | 端口 | 文件路径(Path) | 查询字符串(Query) | 锚点 |
| http | user:pass | www.example.com | 80 | /dir/index.html| ?uid=1&name=cpp | #ch1|
+--------+-----------+-----------------+------+----------------+-------------------+-----+
-
协议方案名(Scheme) :
http。表示本次对话要使用 HTTP 协议规则。 -
登录信息(认证) :
user:pass。早期用来在访问私有资源时带上账号密码(现在极其少见,因为明文不安全)。 -
服务器地址(Host/Domain) :
[www.example.com](https://www.example.com)。指明这台目标主机是谁(背后会通过 DNS 解析成具体的 IP 地址)。 -
服务器端口号(Port) :
:80。指明找这台机器上的哪一个具体网络服务进程。(HTTP 默认是 80,HTTPS 默认是 443,平时浏览器会自动帮我们省略不写)。 -
带层次的文件路径(Path) :
/dir/index.html。进入目标服务器后,到底要拿磁盘里的哪一个具体文件。 -
查询字符串(Query String) :
?uid=1&name=cpp。客户端向服务器传递的额外参数,以?开始,用Key=Value的形式呈现,多个参数用&连接。 -
片段标识符(Fragment/锚点) :
#ch1。告诉浏览器拿到网页后直接滚屏定位到哪个章节(只在浏览器本地生效,不会发给服务器)。
三、 避坑细节:字符转义(UrlEncode 与 UrlDecode)
在 URL 的设计中,像 /、?、:、&、= 已经被赋予了特殊的语法含义(比如 / 代表路径,? 代表参数开始)。
问题来了 :如果用户在百度搜索框里输入的是 C++ 这个词,URL 拼出来岂不是变成了 ?wd=C++?
如果参数里本身就包含 + 或者 &,服务器就会产生歧义,误以为是语法符号!
因此,必须进行字符转义(UrlEncode):
-
转义规则 :将特殊字符的 ASCII 码转成 16 进制数,并在前面加上
%,形成%XY格式。 -
举例 :字符
+的 ASCII 码是 43(十六进制为0x2B),所以C++在 URL 中会被转义为C%2B%2B。 -
收到数据的服务器再执行逆向过程 UrlDecode ,把
%2B还原为+。
四、 HTTP 协议的核心骨架模型
在底层,HTTP 运行在可靠的 TCP 传输协议之上,它有两个极其显著的特性:
bash
+---------------+
| 浏览器/客户端 |
+---------------+
|
1. 发起 TCP 连接 | (三次握手)
v
+---------------+
| Web 服务器 |
+---------------+
|
2. 发送 HTTP Request (我要看 index.html)
---------------------------------------->
|
3. 回复 HTTP Response (给你网页内容)
<----------------------------------------
|
4. 断开连接 (HTTP/1.0 时代单次交互即断开)
- 请求-应答模式(Request-Response):
-
必须由客户端主动发起请求(Request) ,服务端接收处理后返回响应(Response)。
-
服务端不能无缘无故主动给客户端推送网页(除 HTTP/2 某些特殊扩展外)。
- 无连接(早期特性):
- 在早期 HTTP/1.0 中,客户端发完一次请求、收到一次响应后,底层的 TCP 链路就会直接关闭,下次要资源重新连。(后续在 HTTP/1.1 演化出了 Keep-Alive 长连接优化)。
- 无状态(Stateless):
- 服务器像一个患了"脸盲症"的店员。你刚刚向它请求了一次首页,紧接着一秒后又向它发了一次请求,服务器根本记不得"一秒前的你"是谁,它把每一次请求都当成崭新的独立事件。(这就为我们后续讲解 Cookie 和 Session 埋下了伏笔)。
高频面试题精讲
面试题 1:平时说的 URL 和 URI 有什么区别?
-
考察维度:计算机网络基础术语与规范理解。
-
解析:
-
URI(Uniform Resource Identifier,统一资源标识符):是一个大概念,相当于"某人的身份证号",唯一标识网络上的某一个资源。
-
URL(Uniform Resource Locator,统一资源定位符):是 URI 最常见的子集,不仅标识了资源,还指明了"怎么去找到它"(包含了协议名、主机、端口、路径等寻址信息)。
-
标准答案:
URI 是抽象的资源标识概念,而 URL 是 URI 的一种具体实现形态。所有的 URL 都是 URI,但并不是所有的 URI 都是 URL。URL 提供了通过网络获取该资源的方法和物理位置。
面试题 2:为什么 URL 中需要 UrlEncode 编码?空格和中文字符是如何被编码的?
-
考察维度:Web 传输编码机制与边界字符处理。
-
解析:
-
URL 中只允许 ASCII 字符集中的一部分字符无歧义传输。像保留字符(如
?,/,&)具有控制含义,而非 ASCII 字符(如中文)在不同系统和浏览器间的编码实现不同,直接传输容易产生歧义或乱码。 -
标准答案:
为了消除保留字符的语法歧义,并保证非 ASCII 字符在网络传输过程中的一致性与可靠性。
转义方式是将目标字符的字节序列转为十六进制,并在每字节前添加
%(即%XY格式)。例如,空格通常被编码为%20(或在 Query 串中映射为+),中文字符按 UTF-8 编码为 3 组%XX字节。
第二篇:庖丁解牛 ------ HTTP 请求与响应报文的底层细节
一、 核心比喻:HTTP 报文就像一封"公文信件"
在深入代码之前,我们先建立一个直观的画面:
你在现实中寄一封正式的公文信件,通常有固定的排版格式:
- 信封抬头(第一行):写明"特快专递、送往何处、遵循什么邮政标准"。
- 附加信息区(键值对列表):写明"发件人电话、包裹类型、纸张编码格式"。
- 隔离空行:信纸上留出一整行空白,防止上面填写的表单属性和正文混在一起。
- 正文内容(Body):信件最核心的实际公文文本。
HTTP 报文(不管是请求还是响应)的设计哲学与这封信完全一致。它是一种基于文本行(Line-based)的协议。
二、 HTTP 请求报文(Request)的四大结构解剖
当你在浏览器输入网址敲下回车时,浏览器在底层打包好的 HTTP 请求报文字符流长成这样:
bash
+-------------------------------------------------------------------+
| 请求行 | GET /index.html HTTP/1.1\r\n |
+-------------------------------------------------------------------+
| | Host: 127.0.0.1:8080\r\n |
| 请求报头 | User-Agent: Mozilla/5.0 ...\r\n |
| (Header) | Content-Type: application/x-www-form-urlencoded\r\n |
| | Content-Length: 36\r\n |
+-------------------------------------------------------------------+
| 空行 | \r\n |
+-------------------------------------------------------------------+
| 正文 | username=hgtz&password=123 (GET请求通常Body为空) |
+-------------------------------------------------------------------+
我们逐层拆解它的每一个组成部分:
1. 第一行:请求行(Request Line)
由三部分构成,中间用单个空格 隔开,末尾以 \r\n 换行结束:
- 请求方法(Method) :
GET、POST等(告诉服务器你想干什么,是想获取网页还是提交表单)。 - URL / URI :
/index.html(告诉服务器你想要哪一个具体路径下的资源)。 - HTTP 版本(Version) :
HTTP/1.1或HTTP/1.0(告诉服务器当前客户端使用的协议规范版本)。
2. 中间部分:请求报头(Headers)
- 格式为标准的键值对:
Key: Value\r\n。 - 每一对属性占一行,末尾用
\r\n分隔。 - 常见字段:
Host:目标服务器的域名或 IP+端口。User-Agent:用户的操作系统、浏览器内核版本信息。Content-Length:如果后续有正文 Body,这里会明确标明正文到底有多少个字节。
3. 关键分界线:空行(Blank Line)
- 内容只有一个纯粹的
\r\n。 - 核心作用:作为 Header 和 Body 之间的物理分界线。
4. 尾部部分:请求正文(Body)
- 存放实际提交给服务器的数据(例如登录时填写的账号、密码,或者上传的文件二进制流)。
- 如果是普通的
GET页面请求,Body 可以为空。
三、 HTTP 响应报文(Response)的四大结构解剖
服务器收到请求后,磁盘读取文件并组装返回给浏览器的响应报文结构如下:
bash
+-------------------------------------------------------------------+
| 状态行 | HTTP/1.1 200 OK\r\n |
+-------------------------------------------------------------------+
| | Content-Type: text/html; charset=utf-8\r\n |
| 响应报头 | Content-Length: 1024\r\n |
| (Header) | Server: MyCppHttpServer/1.0\r\n |
| | Set-Cookie: sessionid=abcdef123\r\n |
+-------------------------------------------------------------------+
| 空行 | \r\n |
+-------------------------------------------------------------------+
| 正文 | <html><body><h1>Hello World!</h1></body></html> |
+-------------------------------------------------------------------+
1. 第一行:状态行(Status Line)
由三部分构成,同样以空格分隔,末尾以 \r\n 结束:
- HTTP 版本 :
HTTP/1.1 - 状态码(Status Code) :
200(三位数字,机器用来判断结果成功还是失败)。 - 状态码描述(Status Message) :
OK(英文短语,给人看的简短说明)。
2. 中间部分:响应报头(Headers)
Content-Type:告诉浏览器返回的数据类型(如text/html代表网页源码,image/png代表图片),浏览器依据此决定如何渲染。Content-Length:明确告诉浏览器响应 Body 的精确字节数。
3. 空行(Blank Line)与 响应正文(Body)
- 单独一行
\r\n。 - 紧接着就是 HTML 网页源代码、图片二进制字节流或 JSON 字符串。
四、 灵魂拷问:为什么 HTTP 报文必须设计一个"空行"?
TCP 是面向字节流(Byte Stream)的传输协议。在 TCP 层面,没有所谓的"一句话"或"一段报文"的边界,所有数据就像自来水一样混在管道中连续流淌。
如果一个请求中既有 Header 又有 Body,作为接收方(你的 C++ 程序),在底层不断 read() 字节流时:
- 怎么知道所有的 Header 读完了?
- 采用
while(true)按行读取,只要读到某一行的内容正好是\r\n(即长度为 0 的空行),程序立刻知道:Header 全部结束,不能再按键值对解析了!
- 怎么知道 Body 读完了?
- 程序在解析 Header 阶段,提取出
Content-Length: 1024这个数值。 - 跨过空行后,程序精准从 Socket 里再读取
1024个字节,读满后本次 HTTP 报文完整提取,彻底解决 TCP 粘包和半包问题!
高频面试题精讲
面试题 1:请详细描述 HTTP 请求报文和响应报文的结构,它们有哪些相同点与不同点?
-
考察维度:HTTP 报文规范与网络数据封包基础。
-
解析:
-
两者在宏观结构上完全对称,均由 4 部分构成:首行 + Headers + 空行 + Body。
-
核心差异在首行:请求报文首行是请求行 (Method + URL + Version),表达客户端的意图;响应报文首行是状态行(Version + Status Code + Status Desc),表达服务端的处理结果。
-
标准答案:
- 结构:HTTP 请求报文由请求行、请求报头、空行、请求正文组成;HTTP 响应报文由状态行、响应报头、空行、响应正文组成。
- 相同点 :报头与正文之间均使用
\r\n空行作为定界符;报头字段均采用Key: Value\r\n的键值对格式;正文字节长度均由报头中的Content-Length属性明确指定。- 不同点:首行语义不同。请求行声明了请求动作(方法)、目标资源路径与使用的版本;状态行返回了服务端的协议版本、执行状态码及简短状态描述。
面试题 2:HTTP 是基于文本的协议,面对 TCP 字节流传输,它是如何实现报文定界与拆包的?
- 考察维度:应用层协议设计与 TCP 粘包问题解决方案。
- 标准答案:
- 首行与报头定界 :HTTP 使用特殊字符序列
\r\n作为单行结束符。解析器通过行扫描提取请求行和各个报头。- 报头与正文隔离 :当扫描到连续的
\r\n\r\n(即空行)时,标志着报头区域结束。- 正文定界 :根据前面报头中解析出的
Content-Length字段值,按长度读取指定字节数量作为 Body;若采用分块传输编码(Transfer-Encoding: chunked),则按分块长度块逐段读取,直至读取到长度为 0 的终止块。
第三篇:核心请求方法深度剖析:GET 与 POST 的本质差异
核心比喻:明信片与密封纸箱
在 HTTP 协议中,客户端(浏览器)向服务器发送请求时,必须声明一个"动作名称"。这就好比去邮局寄件,你要选择不同的邮政服务。最常用的两个动作就是 GET 和 POST。
GET 方法 = 寄一张"明信片"(用于获取资源)
- 场景:你想从服务器拿一张网页或图片。
- 传参方式 :明信片没有内部空间。如果你想给服务器传点参数(比如告诉服务器你要搜索
C++),只能把字直接写在明信片正面的地址栏里(也就是拼接在 URL 后面,如?wd=cpp)。 - 缺点 :写在明信片表面的字,路过的邮递员(网络节点)一眼就能看光,隐私性极差 (不能用来传密码);且明信片面积有限,传输数据量很小。
POST 方法 = 寄一个"密封纸箱"(用于提交数据)
- 场景:你要向服务器提交注册表单、上传高清照片。
- 传参方式:纸箱内部有巨大的空间(HTTP 的 Body 正文)。你可以把长篇大论的数据塞进纸箱里密封,快递单(URL)上只写目标地址。
- 优点 :数据藏在 Body 里,相对安全 (至少没有暴露在 URL 里让人一眼看穿);纸箱容量极大,可以传输海量数据。
字符画图解:GET 与 POST 的报文差异
bash
【GET 报文:明信片】
+---------------------------------------------------+
| 邮寄地址: GET /search?keyword=cpp HTTP/1.1 | <-- 参数直接暴露在外面
| 寄件人: Mozilla/5.0 ... |
+---------------------------------------------------+
| (空行) |
| (背面无内容,Body 为空) |
+---------------------------------------------------+
【POST 报文:密封纸箱】
+---------------------------------------------------+
| 快递单: POST /login HTTP/1.1 | <-- 地址栏干干净净
| 物品说明: Content-Type: application/json |
+---------------------------------------------------+
| (空行) |
+---------------------------------------------------+
| [包裹内部 Body] |
| username=admin&password=123456 | <-- 数据藏在箱子里
+---------------------------------------------------+
代码级演示:浏览器是如何发起 GET 和 POST 的?
前端网页最常使用 <form> 表单来决定使用哪种方法。
html
<!-- 1. 这是一个 GET 提交表单 -->
<!-- 提交后,浏览器地址栏会变成: http://ip/login?user=admin&pass=123 -->
<form action="/login" method="GET">
账号: <input type="text" name="user">
密码: <input type="password" name="pass">
<input type="submit" value="登录">
</form>
<!-- 2. 这是一个 POST 提交表单 -->
<!-- 提交后,地址栏依然是: http://ip/login,密码数据被藏进了报文 Body 中 -->
<form action="/login" method="POST">
账号: <input type="text" name="user">
密码: <input type="password" name="pass">
<input type="submit" value="登录">
</form>
HTTP 方法家族的其他成员(简单认识)
除了 GET 和 POST 这两位"明星",HTTP 协议还定义了其他几个特定的动作:
- HEAD :类似 GET,但只看信封,不要正文。比如你想看看服务器上那个 10GB 的电影文件有没有更新,先发个 HEAD 请求,服务器只返回 Header(包含文件修改时间和大小),不返回真实的电影流,极其节省带宽。
- OPTIONS :投石问路 。用于询问服务器:"你这里都支持哪些动作?"服务器会回复
Allow: GET, POST, OPTIONS。 - PUT :精准替换。把一段数据传给服务器,覆盖掉服务器上原有的同名文件。
- DELETE :销毁指令。命令服务器删掉 URL 指定的那个文件。
高频面试题精讲
面试题:请说出 GET 和 POST 的本质区别是什么?
- 考察维度:HTTP 核心方法的场景认知与底层机制理解。
- 解析思路:不要只答"GET 是明文 POST 相对安全",要从语义、参数位置、长度限制、幂等性四个专业维度全面展开。
- 满分答案:
- 语义与应用场景:GET 的核心语义是"获取资源",通常用于读取数据;POST 的核心语义是"传输实体主体",通常用于提交表单或上传数据。
- 参数传递位置:GET 的参数通常拼接在 URL 查询字符串(Query String)中提交;POST 的参数则被封装在 HTTP 报文的正文(Body)中提交。
- 数据大小限制:HTTP 协议本身并未限制 GET 的长度,但实际应用中,各大浏览器和服务器会对 URL 的长度做出严格限制(通常在 2KB - 8KB 左右),这导致 GET 传参受限;而 POST 数据在 Body 中,理论上没有长度限制。
- 安全性:POST 比 GET 相对安全,因为 GET 的参数直接暴露在 URL 中,容易被浏览器历史记录、书签或服务器日志记录下来。
- 幂等性与缓存:GET 通常是幂等且可缓存的(多次执行结果相同,不改变服务器状态),浏览器会自动缓存 GET 请求;POST 通常是非幂等的(每次提交都会引起服务器状态改变,如新增一条订单),浏览器默认不会缓存 POST 请求。
第四篇:状态与属性 ------ 状态码全景图与常见 Header
一、 核心比喻:状态码与 Header 到底是个啥?
-
状态码(Status Code) = 医院化验单上的"诊断结论代号"
你去医院抽血验尿,医生不会写一长篇作文给你,而是盖一个章或者写一个数字代码。
-
看到"正常",你就高高兴兴拿着药回家;
-
看到"找错科室",你就得去隔壁挂号;
-
看到"仪器故障",说明是医院的问题不是你的问题。
浏览器拿到状态码也是这样,光看这 3 个数字,就秒懂接下来该展示页面还是报错。
-
Header(报头) = 贴在快递箱子上的"属性面单"
箱子里装的东西叫正文(Body),而贴在箱子外壳上的那张快递单就是 Header。
-
单子上写着"收件人是谁"、"装的是易碎生鲜还是纯文本纸张"、"需不需要冷链保鲜"、"如果本人不在家转交哪里"。
二、 状态码全景家族:五大体检结论
状态码一共由 3 位数字 组成,开头的第一位数字决定了这个事情的"大方向":
bash
+--------+------------------------+--------------------------------------------------+
| 号段 | 专业类别 | 大白话比喻(医院场景) |
+--------+------------------------+--------------------------------------------------+
| 1xx | Informational (信息) | "正在排队叫号/大仪器正在预热,别急,先继续等着或继续送样" |
| 2xx | Success (成功) | "检查一切正常,指标过关,药给你拿好了!" |
| 3xx | Redirection (重定向) | "你跑错诊室了!这个科室搬到新大楼去了,顺着指示牌去找!" |
| 4xx | Client Error (客户端错)| "挂号单写错名字了/没带病历本/你根本没挂这个专家的号!" |
| 5xx | Server Error (服务端错)| "医生突然晕倒了/检验仪器短路冒烟了,不是你的错,是医院的锅" |
+--------+-----------------------+---------------------------------------------------+
最常见的高频状态码解剖:
-
200 OK(交易达成):- 最理想的状态,服务器把你要的网页或数据原封不动打包给你了。
-
301vs302(重定向:找错门了):- 301 Moved Permanently(永久搬家):
- 比喻:老饭店拆迁,门上贴着大字报:"本店永久搬迁至隔壁新街88号,以后不用来老店了,直接去新店!" 浏览器记性很好,下次你再搜老店,它会自动直接去新店。
-
302 Found(临时借用/调头):
-
比喻:老饭店今天内部搞卫生,门口牌子写着:"今天请先到对面分店用餐,明天老店照常营业。" 比如你没登录就去点购物车,服务器临时把你踹到登录页面,登录完再调回购物车。
-
核心搭档 :只要返回 301 或 302,服务器都必须在快递单上贴一个
Location: 新地址,不然浏览器虽然知道找错门了,却不知道往哪儿跳!
-
-
304 Not Modified(协商缓存):- 比喻:"你手里拿的那份复印件和医院档案库里的一模一样,一个字都没改,我就不重新打印给你了,直接看你手里的吧,省纸省钱!"
-
403 Forbidden(禁止入内):- 比喻:"这是院长办公室/机密手术室,你虽然挂了号,但无权查看!"
-
404 Not Found(查无此人):- 比喻:"你拿着 999 号房的挂号单,但整个医院总共只有 5 楼,根本没有这间屋子!"
-
500 Internal Server Error(程序翻车):- 比喻:医院系统突然蓝屏崩溃了,或者后台代码发生了段错误/内存越界。
-
502 Bad Gateway / 504 Gateway Timeout(中介失联):- 比喻:挂号处的前台小护士(代理网关)试图用对讲机呼叫主治医生,结果对讲机那头没人接(502)或者呼叫超时一直没回话(504)。
三、 字符画演示:301 / 302 重定向到底是怎么自动跳转的?
bash
[ 你的浏览器 ] [ 目标服务器 ]
| |
|--------- 1. 敲门:我要看 /old_page.html ----------------->|
| |
|<-------- 2. 回复:302 临时调头 (出门右拐找 /new_page) ------|
| (响应头带上: Location: /new_page.html) |
| |
| (浏览器看到 302 和 Location,不需要用户手动点, |
| 自己默默顺着新地址再次发起请求) |
| |
|--------- 3. 自动敲新门:我要看 /new_page.html ------------>|
| |
|<-------- 4. 回复:200 OK (奉上你要的崭新页面) --------------|
四、 核心 Header 快递单属性:大白话拆解
-
Content-Type(货物类型说明书):- 告诉浏览器送来的是啥:如果是
text/html,浏览器就当成网页画出来;如果是image/png,就当成图片展示;如果是application/json,就当成接口数据解析。
- 告诉浏览器送来的是啥:如果是
-
Content-Length(货物精准称重):- 标明箱子里的正文刚好有
1024个字节。防止管道里水流太快,接收端不知道从哪里截断。
- 标明箱子里的正文刚好有
-
Host(总店地址):- 告诉服务器:"虽然这台物理机器上架了好多网站,但我这次是找张三总店的"。
-
User-Agent(客户端名片):- 告诉服务器:"我是 Windows 电脑上的 Chrome 浏览器"还是"我是 iPhone 上的微信内置浏览器",服务器可以根据这个决定给你推电脑版网页还是手机版网页。
-
Referer(引荐人是谁):- 记录"我是从哪个网页点击超链接跳转过来的",用来防止别人盗刷流量或统计广告来源。
-
Connection: keep-alive(保持电话别挂):-
比喻:
-
close(短连接):你问一句"明天开门吗?",对方回一句"开",马上把电话挂断(TCP 挥手);下一秒你想再问"几点开门?",又得重新拨号(TCP 握手)。 -
keep-alive(长连接):问完一句先别挂断电话,保持通话线路通畅,等我把后面的三五个问题一次性全问完,最后再一起挂机,极其省时省力!
-
高频面试题精讲
面试题 1:HTTP 状态码 301 与 302 的区别是什么?搜索引擎对此有什么不同反应?
-
考察维度:重定向机制与网络 SEO 原理。
-
通俗解析:
-
301 是"这房子我彻底卖了,以后都不在这里住了",所以浏览器和搜索引擎会把老地址直接从脑子里抹掉,改成新地址。
-
302 是"我今天临时出差,有事去对面办公室找我",老地址依然有效,浏览器和搜索引擎不敢轻易删掉老地址的记录。
-
标准答案:
语义区别:301 代表永久重定向(Moved Permanently),表示旧 URL 彻底废弃,资源永久迁移到新 URL;302 代表临时重定向(Found),表示旧 URL 依然有效,仅本次请求临时访问新 URL。
浏览器缓存:浏览器会永久缓存 301 的重定向结果,下次用户输入旧网址直接跳转新地址无需再问服务器;而 302 不会被浏览器默认缓存,每次都要重新向服务器求证。
搜索引擎区别:搜索引擎爬虫遇到 301 会将旧网址的权重转移给新网址并更新收录库;遇到 302 则会继续保留旧网址的收录和权重,只抓取临时内容。
面试题 2:HTTP 报头中的 Connection: keep-alive 是什么意思?与 TCP 的 Keepalive 是一回事吗?
- 考察维度:应用层长连接机制与网络分层辨析。
- 标准答案:
HTTP 的 Keep-Alive(应用层) :指的是持久连接(长连接)。允许客户端和服务器在同一个 TCP 连接管道上连续收发多个 HTTP 请求与响应,避免了每次请求都要重新进行 TCP 三次握手和四次挥手的巨大开销。
两者的本质区别:
HTTP Keep-Alive 是应用层的连接复用机制(为了性能提速,不轻易关通道);
TCP Keepalive 是传输层的保活心跳探测机制(在链路长时间没数据流动时,系统定时发送空探测包,检测对方是否已经拔网线或死机断网)。
第五篇:状态保持加餐 ------ Cookie 与 Session 机制(网站到底是怎么认出你的?)
一、 核心比喻:游乐园的"手环门票"与"VIP储物柜"
在第一篇中我们讲过:HTTP 是一个无状态协议。
-
无状态比喻:服务器就像一个患了严重"脸盲症"的游乐园检票员。你前一秒刚买了门票进园,后一秒在园内买冰淇淋时,检票员又把你当成陌生人,冲你喊:"请先买票!"
-
矛盾点:但我们在刷 B 站、淘宝时,只要登录了一次,接下来刷视频、加购物车都不需要重新输密码,网站仿佛"认得"我们。
-
破局之道:
-
Cookie(用户手腕上的手环) :检票员不记你的脸,但在你第一次买票时,他在你的手腕上盖个章或扣一个数字手环(存放在你的浏览器本地)。之后你每次路过任何设施,伸出手环晃一下,检票员看一眼手环编号就放行。
-
Session(游乐园后台的贵宾储物柜) :你的私人资产(钱包余额、购物车清单、真实姓名)如果全印在手环上,手环丢了或被别人看光就全露馅了。所以游乐园把你的贵重物品锁在后台的储物柜(服务器内存/数据库)里,手环上只写一个储物柜钥匙编号(Session ID)!
二、 阶段演进:从"纯 Cookie"到"Cookie + Session 配合"
1. 方案一:纯 Cookie 时代(手环上直接写明文信息)
-
流程 :用户输入账号密码登录 → \to → 服务器验证成功,通过响应头返回
Set-Cookie: username=zhangsan; pass=123456→ \to → 浏览器存在本地 → \to → 以后每次请求自动带上Cookie: username=zhangsan; pass=123456。 -
致命缺陷:
-
极度危险:Cookie 是明文保存在客户端电脑/浏览器里的文件,黑客一旦通过木马或 XSS 脚本窃取了 Cookie,用户的账号密码直接彻底泄露!
2. 方案二:Cookie + Session 机制(工业界标准解法)
为了兼顾"记住用户"与"保护私密数据",架构做了分工演进:
-
服务端(Session):在服务器内存中创建一个结构体对象,保存用户的真实私密数据(用户名、登录时间、购物车等)。
-
客户端(Cookie) :客户端只保存一串毫无规律的随机字符串(即
Session ID,例如3260880733)。
三、 字符画全流程演示:登录与会话保持
bash
[ 浏览器 (客户端) ] [ Web 服务器 ]
| |
|---- 1. POST /login (提交账号: zhangsan, 密码: 123) -------->|
| | (验证账号密码正确)
| | 1. 在内存创建 Session 对象
| | {user: "zhangsan", vip: true}
| | 2. 生成随机 Session ID: "8888"
| | 3. 建立映射: Map["8888"] = Session
| |
|<--- 2. HTTP/1.1 200 OK -----------------------------------|
| Set-Cookie: sessionid=8888; path=/; HttpOnly |
| |
(浏览器默默把 "sessionid=8888" 存入本地) |
| |
|---- 3. GET /my_cart (进入购物车页面) ---------------------->|
| Cookie: sessionid=8888 | (浏览器自动在请求头带上手环)
| |
| | 4. 从 Map 查 "8888",拿到 Session
| | 5. 提取出当前是 "zhangsan",读取购物车 |
|<---- 4. HTTP/1.1 200 OK (渲染 zhangsan 的专属购物车页面) ----|
四、 Cookie 的核心属性与安全控制
服务器在给浏览器发手环(Set-Cookie)时,可以追加许多控制参数:
-
expires=<UTC时间>/max-age=<秒数>(手环有效期): -
会话 Cookie:不设置过期时间,浏览器一关闭,Cookie 立刻销毁。
-
持久 Cookie:设置了过期时间(如 7 天免登录),Cookie 会以文件形式存入硬盘,关机重启依然有效。
-
path=/(作用路径): -
限制 Cookie 只能在访问特定路径(如
/a/b)时才提交,访问其他无关路径时不浪费带宽发送。 -
HttpOnly(防止脚本盗窃,极重要): -
加上这个标记后,网页里的 JavaScript 脚本就无法读取 该 Cookie,专门用于防御 XSS(跨站脚本攻击) 窃取用户身份。
-
Secure(仅限安全通道): -
限制该 Cookie 只能在 HTTPS 加密连接下传输,防止在 HTTP 明文下被黑客窃听。
五、 C++ 代码模拟演示:轻量级 Session 管理器
在后端开发中,Session 管理器的底层核心其实就是一个带线程安全锁的哈希表:
cpp
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <ctime>
// 1. Session 数据载体
class Session {
public:
Session(const std::string &username)
: _username(username), _login_time(time(nullptr)) {}
std::string _username;
time_t _login_time;
};
// 2. Session 管理器
class SessionManager {
public:
// 用户登录成功,创建并登记 Session
std::string AddSession(const std::string &username) {
// 生成一个唯一 ID(工业界常使用 UUID 算法)
std::string session_id = std::to_string(rand()) + "_" + std::to_string(time(nullptr));
_sessions[session_id] = std::make_shared<Session>(username);
return session_id;
}
// 根据请求头里的 Session ID 检索用户身份
std::shared_ptr<Session> GetSession(const std::string &session_id) {
auto it = _sessions.find(session_id);
if (it == _sessions.end()) {
return nullptr; // 没查到或已过期
}
return it->second;
}
private:
std::unordered_map<std::string, std::shared_ptr<Session>> _sessions;
};
高频面试题精讲
面试题 1:请详细说一下 Cookie 与 Session 的区别与联系。
-
考察维度:Web 状态管理与会话跟踪核心机制。
-
解析:
-
从存储位置 、安全性 、性能开销 、容量大小四个维度对比。
-
标准答案:
存储位置 :Cookie 存储在客户端浏览器 本地;Session 存储在服务端(内存、Redis 缓存或数据库中)。
安全性 :Cookie 存放在客户端容易被伪造、篡改或通过 XSS 窃取;Session 数据保存在服务端,客户端仅持有无实际含义的
Session ID,因此 Session 的安全性远高于纯 Cookie。服务器资源:每个活跃用户都会在服务器占用一定的 Session 内存开销;而 Cookie 占用的是用户本地存储,对服务器内存零消耗。
协同工作 :HTTP 是无状态协议,通常需要依靠 Cookie 作为载体,在每次 HTTP 请求中自动携带
Session ID,服务端依此识别对应的 Session 对象,两者协同实现用户会话状态的保持。
面试题 2:如果用户的浏览器禁用了 Cookie,Session 还能正常工作吗?如果能,该怎么做?
-
考察维度:对 Session ID 传输通道的理解深度。
-
解析:
-
Cookie 只是传输
Session ID最常用的通道,并非唯一通道。 -
标准答案:
可以正常工作 。当浏览器禁用 Cookie 时,可以通过以下两种替代方案回传
Session ID:
- URL 重写(URL Rewriting) :服务器在返回的所有超链接和重定向 URL 后面自动拼接 Session ID 参数,如
[http://www.site.com/index?jsessionid=8888](http://www.site.com/index?jsessionid=8888)。- 自定义 HTTP Header 传递(Token 机制) :前端通过 Ajax/Fetch 请求时,将身份令牌(如 Token / Session ID)显式放在自定义请求头(如
Authorization: Bearer <token>)中发送给服务端。
第六篇:终极安全加餐 ------ HTTPS 协议与密码学破局
一、 核心比喻:透明玻璃瓶与"中间人劫持"
-
HTTP 的致命硬伤(透明玻璃瓶):
-
普通的 HTTP 就像你用一个完全透明的玻璃瓶给朋友寄信。
-
快递在经过沿途的路由器、Wi-Fi 热点、运营商基站时,任何一个路过的"快递员"(黑客或被入侵的设备)都能把瓶子里的字看得一清二楚(数据泄露 ),甚至能拧开盖子把你的信撕掉换上一张假信(数据篡改)。
-
经典现实案例:早期的"运营商劫持",你想下载"天天动听",点击下载后弹出来的却是"QQ 浏览器",因为中间路由器直接把你的 HTTP 响应报文内容给换了!
-
HTTPS 的破局本质:
-
HTTPS = HTTP + SSL/TLS 加密层。
-
相当于在玻璃瓶外面套上了一层用现代密码学打造的坚固保险箱,只有真正的收发双方才有钥匙打开。
二、 密码学前置工具箱:两把锁与数字指纹
在推演方案前,我们需要先备齐三件密码学武器:
- 对称加密(同一把钥匙):
- 特点 :加密和解密用的是同一把钥匙。
- 比喻:老式弹簧锁,你和朋友手里各配一把一模一样的铁钥匙,锁上和开锁都用它。
- 优缺点 :加解密速度极快、算力消耗极低;但缺点是"如何把钥匙安全送给对方"。
- 非对称加密(公钥与私钥):
-
特点 :钥匙是一对儿,公钥(公开给全世界)和 私钥(自己死死藏好)。
-
比喻:
-
公钥 = 敞开的特制挂锁(任何人都可以拿来把箱子锁上);
-
私钥 = 唯一的开锁钥匙(锁上一旦扣死,全世界只有拿着私钥的主人能打开)。
-
优缺点 :安全性极高,无需提前共享秘密;但数学运算极其复杂,加解密速度非常慢。
- 数据摘要 / 数字指纹(Hash 散列):
- 特点:通过 MD5/SHA 算法把任意长的数据压缩成一串固定长度的"指纹"。
- 特性:不可逆(无法从指纹倒推原文)、极其敏感(原文改动一个标点符号,生成的指纹面目全非)。用于核对内容是否被动过手脚。
三、 方案递进推演:HTTPS 是如何一步步进化出来的?
方案 1:只用对称加密(行不通)
- 做法 :浏览器和服务器商量好一个密钥
key=8888,全程用这个密钥加密通信。 - 死穴 :第一次建立连接时,浏览器怎么把
8888告诉服务器?如果直接明文发过去,路上的黑客同样拿到了8888,后续加密形同虚设(陷入"先有鸡还是先有蛋"的悖论)。
方案 2:只用非对称加密(行不通)
- 做法:服务器把自己的"公钥"明文发给浏览器。浏览器给服务器发消息时用公钥加密,只有服务器的私钥能解开,看似很安全。
- 死穴:
- 单向安全:服务器给浏览器回信时怎么办?如果服务器用私钥加密,全世界谁都能用公开的公钥解密,黑客在中间依然能偷看!
- 性能崩溃:所有网页图片全用非对称加密,CPU 会被活活算死。
方案 3:非对称加密 + 对称加密(混合双打,看似完美)
- 思路:用非对称加密来"安全运送钥匙",用对称加密来"传输实际数据"。
- 流程:
- 服务器把公钥发给浏览器。
- 浏览器在本地随机生成一个对称密钥
key=8888。 - 浏览器用服务器的公钥把
8888加密后发给服务器。 - 服务器用私钥解密拿到
8888。 - 双方后续都用
8888进行极速的对称加密通信!
- 致命漏洞 :中间人攻击(Man-In-The-Middle, MITM)!
四、 灵魂一击:什么是"中间人攻击"?
如果在最开始发公钥的阶段,黑客就蹲在路由器上搞鬼呢?
bash
[ 浏览器 ] [ 蹲在中间的黑客 ] [ 真实服务器 ]
| | |
|<-- 1. 拦截真正公钥S, 换成黑客公钥M ---| <----- 1. 发送自己的公钥 S -----------|
| | |
(拿到黑客公钥M,误以为是服务器的) | |
2. 生成密钥 8888, 用公钥M加密 | |
| | |
|---- 2. 发送加密后的 8888 ---------->| |
| | 3. 黑客用自己的私钥M'解密! |
| | 【黑客成功拿到密钥 8888!】 |
| | 4. 黑客用服务器公钥S重新加密 8888 |
| | |
| |--- 5. 把重新加密的报文转交 --------->|
| | | (解密拿到 8888)
问题本质 :浏览器拿到的那个公钥,无法证明它到底是不是真正服务器的公钥!
五、 终极破局:CA 机构与数字证书(方案 5)
为了证明"这个公钥确实属于百度而不是黑客",引入了权威的第三方公证处 ------ CA 机构(Certificate Authority)。
1. 什么是数字证书?
就像国家的派出所给公民发身份证一样,CA 机构给服务器发数字证书 。
证书包含两部分:
- 明文信息 :证书颁发机构、网站域名、有效时间、服务器真正的公钥。
- 数字签名(防伪防调包钢印) :CA 机构把明文信息通过 Hash 算出一个摘要,然后用 CA 自己的私钥 对这个摘要进行加密,生成数字签名。
bash
+--------------------------------------------------------------------------+
| 数字证书 (Certificate) |
| +----------------------------------------------------------------------+ |
| | 明文信息:域名 (qq.com)、有效期、服务器真实公钥 (pub_server) | |
| +----------------------------------------------------------------------+ |
| | 数字签名:CA私钥[ Hash(明文信息) ] | |
| +----------------------------------------------------------------------+ |
+--------------------------------------------------------------------------+
2. 浏览器是如何验真伪的?(防篡改与防调包)
操作系统和浏览器在出厂安装时,就已经在系统内部内置了全球各大可信 CA 机构的根公钥!
当浏览器收到服务器发来的证书后:
- 防篡改验证:
- 浏览器用系统内置的 CA 公钥解开数字签名,得到原始的
摘要1。 - 浏览器自己把证书里的明文信息用同样算法 Hash 一下,算出
摘要2。 - 对比 :若
摘要1 == 摘要2,说明明文信息里的服务器公钥没有被任何人修改过!
- 防调包验证:
- 如果黑客去 CA 机构给自己的网站申请了一张合法的真证书,把服务器证书整体替换掉呢?
- 浏览器一查证书明文里的域名是
hacker.com,而用户地址栏输入的是qq.com,域名不匹配,浏览器立刻弹出红色大字警告:"您的连接不是私密连接!"
六、 全流程闭环:HTTPS 的"三组密钥"黄金协同
整个 HTTPS 建立安全通信的完整生命周期,由 三组密钥 完美配合完成:
bash
[ 客户端 / 浏览器 ] [ 真实服务端 ]
| |
|------------ 1. Client Hello (请求建立 HTTPS 连接) ------->|
| |
|<----------- 2. Server Hello (带上 CA 颁发的数字证书) ------|
| |
(第1组密钥生效: 用内置CA公钥解密签名, |
校验服务器证书真实性与公钥合法性) |
| |
(在本地随机生成对称密钥 R) |
| |
|------ 3. (第2组密钥生效: 用证书里的服务器公钥加密密钥R) ------>|
| | (服务器用自己的私钥解密,
| | 成功安全拿到对称密钥 R)
| |
(第3组密钥生效: 双方从此开启纯对称加密数据传输,使用密钥 R 进行加解密) |
| |
|<========== 4. 双向密文传输网页与数据 (极速且安全) ===========>|
- 第一组(CA 非对称密钥) :用于让客户端安全验证证书,拿到合法的服务器公钥。
- 第二组(服务器非对称密钥) :用于让客户端安全传输对称密钥 R 给服务器。
- 第三组(对称密钥 R) :客户端与服务器后续传输业务数据时的真正加密钥匙。
高频面试题精讲
面试题 1:HTTPS 建立连接的完整过程(SSL/TLS 握手)是怎样的?
- 考察维度:计算机网络安全传输协议全流程。
- 标准答案:
- 客户端发起请求 :客户端向服务端发送
Client Hello,包含支持的 TLS 版本、加密套件列表和一个客户端随机数。- 服务端返回证书 :服务端回复
Server Hello,确定加密套件,生成服务端随机数,并附带 CA 颁发的数字证书(内含服务器公钥)。- 客户端验证证书与协商密钥:客户端利用本地操作系统内置的 CA 根公钥校验数字签名,确认证书合法后,生成预主密钥(Pre-master secret),并用证书里的服务器公钥加密后发送给服务端。
- 生成对称密钥并开启加密通信:服务端利用自己的私钥解密拿到预主密钥。双方结合前面的随机数在本地计算出相同的对称密钥(Master Secret),后续所有的 HTTP 数据均采用该对称密钥进行加解密通信。
面试题 2:为什么数字签名不直接对整个证书明文进行非对称加密,而是要先 Hash 生成摘要再加密?
- 考察维度:密码学算力开销与工程设计权衡。
- 标准答案:
- 提升运算性能:非对称加密算法(如 RSA)非常消耗 CPU 算力,加密的数据块越长,计算耗时越呈指数级上升。证书明文信息较长,直接加密会导致网络握手显著变慢。
- 缩短密文长度:利用 Hash 算法(如 SHA-256)可以将任意长度的明文压缩成固定长度(如 256 位)的数字摘要,再对定长摘要进行非对称加密,大幅减少了计算量与网络传输体积。
面试题 3:为什么有了对称加密和非对称加密,HTTPS 依然必须要引入 CA 数字证书?
- 考察维度:中间人攻击与身份认证机制。
- 标准答案:
仅靠非对称加密无法防范中间人攻击(MITM) 。黑客可以在握手初期拦截并替换服务端的公钥为自己的公钥,导致客户端误用黑客公钥加密密钥。
引入由权威 CA 机构颁发并带有数字签名的证书,可以通过操作系统的信任链机制,确保证书中的公钥确实归属于目标域名,解决了"公钥可信度与防伪造"的根本问题。
自问自答
一、 HTTP 协议基础与报文结构
Q1:HTTP 协议常被称为"无状态"协议,这里的"无状态"是什么意思?
- 标准作答 :
"无状态"指服务器不会主动记录或记忆客户端的历史交互上下文。客户端前后两次发起的独立请求,在服务器看来是完全没有关联的崭新事件。这种设计简化了服务器架构,但为了实现用户登录等功能,必须额外引入 Cookie 和 Session 机制来"保持状态"。
Q2:HTTP 报文(请求或响应)统一由哪四个部分组成?中间的"空行"有什么不可替代的作用?
- 标准作答:
- 组成:首行(请求行/状态行)、报头(Headers)、空行(Blank Line)、正文(Body)。
- 空行的作用 :HTTP 是基于文本行的协议,底层运行在无边界的 TCP 字节流上。空行(单独的
\r\n)作为物理定界符,用于明确告知接收端的解析程序:"报头属性已经全部读取完毕,接下来要读取的是正文数据"。
Q3:为什么 URL 中的中文字符或特殊符号必须进行 UrlEncode 编码?
- 标准作答 :
URL 规范中包含了许多保留字符(如?表示参数开始,&表示参数连接,/表示路径层级)。如果直接在参数中传输这些符号,会引起服务端解析时的语法歧义。UrlEncode 将非 ASCII 字符或保留字符转换为%XY格式(如空格转为%20),确保了网络传输的安全性和一致性。
二、 请求方法与状态码
Q4:从初学者的直观使用角度来看,GET 和 POST 最基础的区别是什么?
- 标准作答:
- 应用场景:GET 用于向服务器"索取/查询"数据;POST 用于向服务器"提交/写入"数据。
- 参数位置:GET 的参数直接拼接在 URL 地址栏末尾,暴露在外且受长度限制;POST 的参数封装在 HTTP 报文的正文(Body)内部,地址栏不可见且容量极大。
Q5:遇到 200、404、500、502 这四个常见状态码,分别代表系统出了什么状况?
- 标准作答:
- 200 OK:一切正常,请求成功,服务端已返回所需数据。
- 404 Not Found:客户端请求的资源路径不存在(往往是 URL 输错了,或者文件被服务端删除了)。
- 500 Internal Server Error:服务端代码发生了内部崩溃(如空指针、除零错误、数据库连接失败),是服务器程序的责任。
- 502 Bad Gateway:充当代理或网关的服务器正常,但它向上游真实的业务服务器请求数据时,上游服务器无响应或连接失败。
Q6:响应报头中的 Content-Type 和 Content-Length 分别告诉了浏览器什么信息?
- 标准作答:
Content-Type:标明了正文的数据格式(如text/html是网页,image/png是图片,application/json是接口数据),决定了浏览器用什么引擎来渲染或解析。Content-Length:给出了正文精确的字节数,浏览器依赖该数值从 TCP 字节流中截取完整、准确的报文段,防止少读或多读。
三、 Cookie 与 Session
Q7:Cookie 和 Session 在物理存储位置上最本质的区别是什么?
- 标准作答 :
Cookie 存储在客户端(用户的浏览器本地硬盘或内存中) ;Session 存储在服务端(服务器的内存、数据库或专门的缓存组件中)。
Q8:为什么在真实开发中,绝对不能只用 Cookie 来保存用户的账号密码实现免密登录?
- 标准作答 :
Cookie 是保存在客户端的纯明文文件。如果直接记录账号密码,一旦用户的电脑被植入木马,或者遭遇跨站脚本攻击(XSS),黑客可以直接读取到真实的密码信息。必须采用 Session 机制,在 Cookie 中只保存一串毫无业务含义的随机Session ID作为凭证。
四、 HTTPS 与加密基础
Q9:对称加密和非对称加密在密钥使用上有什么区别?
- 标准作答:
- 对称加密 :加密和解密使用的是同一把密钥(速度极快,适合大数据量传输)。
- 非对称加密 :使用的是一对密钥(公钥和私钥)。公钥加密的数据只有私钥能解开,私钥加密的数据只有公钥能解开(安全性极高,但数学运算复杂、速度极慢)。
Q10:HTTPS 既然已经用非对称加密来保护通信了,为什么还必须要引入 CA 机构颁发的数字证书?
- 标准作答 :
单纯依靠非对称加密无法证明"公钥的真实归属者"。黑客可以在客户端和服务器建立连接之初,拦截真实公钥,并将自己的"伪造公钥"发给客户端(中间人攻击)。CA 机构颁发的数字证书通过其权威的数字签名,向客户端担保了该公钥确实属于目标服务器,从根本上防止了公钥被掉包。