⽹络原理-TCP/IP
①应用层:规则 → 格式 → 实际用途讲解↓
(1)定义应用之间怎么通信比如:浏览器怎么请求网页、APP 怎么跟服务器发数据。
- 谁先说话
- 什么时候发请求
- 什么时候回响应
- 出现错误怎么办
- 一次会话怎么开始、怎么结束
比如 HTTP 协议就明确规定:
- 客户端先发请求行(GET / HTTP/1.1)
- 再发请求头
- 最后发请求体
- 服务器收到后按格式返回状态码、响应头、响应体.
(2)规定数据格式
- 纯文本 / 简单文本格式:最原始
- xml:比较原始,可读性好,冗余多
- json:主流方式,可读性好,冗余一般
- protobuf:高性能下使用,可读性差,冗余最小
(3)面向具体业务
(聊天、发邮件、看网页、传文件、DNS 解析...... 都由应用层协议实现)
应用层是最贴近用户需求的一层,每一种业务都对应一套专用的应用层协议:
- 看网页、接口请求 → HTTP/HTTPS
- 把域名翻译成 IP → DNS
- 发邮件 / 收邮件 → SMTP / POP3 / IMAP
- 传文件 → FTP
- 聊天、实时消息 → WebSocket、MQTT
- 自动获取 IP → DHCP
HTTP :采用一问一答的 请求 - 响应 模型
客户端发送一个请求,服务器返回一个响应
还有其他模型:多问一答,一问多答,多问多答等等
②抓包应用层数据分析(这里就不介绍抓包用法了):
++请求数据包++:
GET /g?b=qq&ek=AQLyEg1WWwyLicQv7eUyJ6JFiaj1gIM4QzibsXlmd4kM69qEQh9oVjFeJqKcm7ictdy5gN1Po2Wbol5ltAEgYmqDqUKHYEQSkb2At3KYaHTzpda3S0eDIg4yA8YlGVvQdg&s=100 HTTP/1.1\r\n
Host: qh.qlogo.cn\r\n
Accept: */*\r\n
Connection: Keep-Alive\r\n
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2)\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
\r\n
第一行[方法+路径(不是完整url)+版本](软件里是一行,这里为了方便看换行了):
GET /g?b=qq&ek=AQLyEg1WWwyLicQv7eUyJ6JFiaj1gIM4QzibsXlmd4kM69qEQh9oVjFeJqKcm7ictdy5gN1Po2Wbol5ltAEgYmqDqUKHYEQSkb2At3KYaHTzpda3S0eDIg4yA8YlGVvQdg&s=100 HTTP/1.1\r\n
(1)请求方法:GET 还有POST等等
(2)路径:一般就是HOST后面的部分,比如
https://www.bilibili.com/video/BV1PuP9zDE1n/?spm_id_from=333.1007.tianma.1-3-3.click&vd_source=ff39d66ec682229d79998a749df90847
一般网页最开始的网址往后的都是路径,比如这里的www.bilibili.com就是下一个HOST,接上这个路径之后才变成URL
/g:接口路径?后面是参数:b=qq:业务类型 QQek=xxx:加密 key / 头像标识s=100:尺寸 100×100
(3)版本号:在路径的后面,原网页不会显示出来,抓包才能看见,刚刚的数据包里的HTTP/1.1\r\n就是版本号
为什么有的时候方法后直接给了完整url?
→ 客户端用「代理服务器」上网时
GET https://www.baidu.com/ HTTP/1.1其他99% 的正常情况
→ 方法后面只写路径,Host 单独一行
GET /index.html HTTP/1.1 Host: www.baidu.com
第2-n行[各种Header请求头]:从刚刚的首行后面都是各自请求头,直到出现一个留出来的空行,表示请求头结束
请求头一般有:
1. 通用类(最基础)
- Host:访问哪个域名(HTTP/1.1 必须有)
- User-Agent:你是什么浏览器 / 设备
- Accept:你能接收什么类型内容(图片、文本等)
- Connection:是否长连接 Keep-Alive
2. 缓存控制类
- Cache-Control:要不要缓存、缓存多久
- Pragma:老版本的 no-cache
- If-Modified-Since:问服务器文件有没有更新
3. 身份 / 状态类
- Cookie:浏览器带给服务器的身份信息
- Authorization:登录令牌(账号密码类)
4. 内容类型类
- Content-Type:发送的数据是什么格式(JSON / 表单)
- Content-Length:数据长度(GET 一般没有,POST 才有)
5. 来源 / 安全类
- Referer:从哪个页面跳过来的
- Origin:跨域时用,表明来自哪个域名
- Upgrade-Insecure-Requests:要求升级成 HTTPS
空行后:body部分:body不是每一个数据包都有的
- **GET 请求:没有请求体(body)**所有参数都放在 URL 里,头结束就结束。
- POST / PUT 请求:才有请求体用来传表单、JSON、文件等。
POST /api/login HTTP/1.1 [首行]
Host: www.example.com [各种请求头]
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Connection: keep-alive
username=admin&password=123456 [body]
请求体(Body)的作用(报告直接抄)
请求体(Body)是客户端向服务器提交的业务数据内容,主要作用:
传递大量 / 敏感数据不像 GET 只能把参数放 URL,Body 可以放更长、更隐私的数据(密码、手机号、表单内容)。
提交表单、上传信息登录、注册、发评论、上传文件、提交订单,都用 Body 传输。
传输复杂结构可以传 JSON、表单、文件二进制,功能比 URL 参数强得多。
更安全Body 不会显示在地址栏,HTTPS 下会被加密,比 URL 更适合敏感信息。
GET、POST、PUT、DELETE 这些方法全都只出现在客户端发送的请求数据包中,响应数据包里没有任何方法。
++响应数据包++(注意响应没有GET,POST等方法,也不一定有body):
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Content-Length: 56
Connection: keep-alive
<html>
<head><title>测试页面</title></head>
<body>Hello</body>
</html>
第一行[版本号+状态码+状态码解释]:
(1)版本号:HTTP/1.1
(2)状态码:200(请求成功)
(3)描述:OK
第2-n行[各种Header请求头]:
Server: nginx
Content-Type: text/html; charset=UTF-8
Content-Length: 56
Connection: keep-alive
Server: 服务器软件(nginx)Content-Type: 响应体类型是 HTMLContent-Length: 响应体长度Connection: 长连接
直到空行才结束
空行后:
<html>
<head><title>测试页面</title></head>
<body>Hello</body>
</html>
body部分,这里body也不是每一个响应数据包都有,主要内容是服务器返回给浏览器的网页内容
③HTTP请求(Request)
(1)URL
++URL基本格式:++
平时我们俗称的 "网址" 其实就是 URL。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
以 B 站网址为例:
https://www.bilibili.com/video/BV1PuP9zDE1n/spm_id_from=333.1007.tianma.1-3-3.click
拆分对应:
- 协议:
https - 主机名:
www.bilibili.com - 路径:
/video/BV1PuP9zDE1n/ - 查询参数:
spm_id_from=333.1007.tianma.1-3-3.click
?之后就是查询参数
host和查询参数之间就是路径
有端口号的:
http://127.0.0.1:8080/login?username=admin&pwd=123
协议://IP: 端口 / 路径?参数 1 = 值 1 & 参数 2 = 值 2
URL:
http://127.0.0.1:8080/login?username=admin&pwd=123
1. 协议(Scheme)
http
2. 主机(Host / IP)
127.0.0.1
3. 端口(Port)
8080
4. 路径(Path)
/login
5. 查询参数(Query String)
从 ? 开始username=admin&pwd=123
- 参数 1:
username=admin - 参数 2:
pwd=123 - 多个参数用
&连接
++URL encode:++
URL encode = 把网址里不能直接显示的特殊字符,转换成 % 开头的编码格式,让网址能安全传输。
URL 中像
/:?&=#这类字符,已经被 URL 语法赋予了固定含义,用来分隔协议、主机、路径、参数。如果你的参数内容里本身也出现这些字符 (比如密码里带
?或&),浏览器和服务器就会误解结构,导致参数解析错误。所以必须用 URL 编码 把它们转成
%XX格式,避免冲突。
转义的规则如下:
将需要转码的字符转为 16 进制,然后从右到左,取 4 位 (不足 4 位直接处理),每 2 位做一位,前面加上 %,编码成 % XY 格式
++HTTP 请求方法:++
| 方法 | 说明 | 支持的 HTTP 协议版本 |
|---|---|---|
| GET | 获取资源 | 1.0、1.1 |
| POST | 传输实体主体 | 1.0、1.1 |
| PUT | 传输文件 | 1.0、1.1 |
| HEAD | 获得报文首部 | 1.0、1.1 |
| DELETE | 删除文件 | 1.0、1.1 |
| OPTIONS | 询问支持的方法 | 1.1 |
| TRACE | 追踪路径 | 1.1 |
| CONNECT | 要求用隧道协议连接代理 | 1.1 |
| LINK | 建立和资源之间的联系 | 1.0 |
| UNLINE | 断开连接关系 | 1.0 |
其中最重要的是GET,POST,方法
(1)GET:
GET 是最常用的 HTTP 方法,常用于获取服务器上的某个资源。
在浏览器中直接输入 URL,此时浏览器就会发送出一个 GET 请求
HTML 中的 link、img、script 等标签,也会触发 GET 请求
即除了你手动在地址栏输网址,网页里的这些标签也会自动偷偷去服务器拿东西
当你访问一个网页(比如
www.baidu.com)时,服务器返回给你的不仅仅是一个 HTML 文件,还包含了很多代码。当浏览器解析这份 HTML 代码时,发现里面有这些标签:
<link rel="stylesheet" href="style.css">(引用 CSS 样式)<img src="logo.png">(引用图片)<script src="app.js"></script>(引用 JavaScript 文件)浏览器发现这些标签里有
href或src属性(指向了外部资源),它就会自动发起 GET 请求,去服务器把这些文件取回来。直观的过程举例:
假设你访问
index.html:
- 浏览器 :我要
index.html-> 发 GET 请求 -> 服务器- 服务器 :返回
index.html给浏览器- 浏览器 (开始解析 HTML):
- 看到
<img src="a.png">-> 立刻发 GET 请求 -> 拿a.png- 看到
<script src="b.js">-> 立刻发 GET 请求 -> 拿b.js- 看到
<link href="c.css">-> 立刻发 GET 请求 -> 拿c.css
GET 请求的特点:
・首行的第一部分为 GET
・URL 的 query string 可以为空,也可以不为空
・header 部分有若干个键值对结构
・body 部分为空
(2)POST方法:
POST 方法也是一种常见的方法,是 HTTP 协议里最核心的请求方法之一 ,核心作用就是:向服务器提交 / 发送数据,让服务器执行「写入、创建、更新」这类操作。
POST 请求的特点:
・(数据包)首行的第一部分为 POST
・URL 的 query string 一般为空 (也可以不为空)
・header 部分有若干个键值对结构
・body 部分一般不为空,body 内的数据格式通过 header 中的 Content-Type 指定,body 的长度由 header 中的 Content-Length 指定
补充内容:
①GET和POST的区别:
・语义不同: GET 一般用于获取数据,POST 一般用于提交数据.
・GET 的 body 一般为空,需要传递的数据通过 query string 传递,POST 的 query string 一般为空,需要传递的数据通过 body 传递
・GET 请求一般是幂等的,POST 请求一般是不幂等的. (如果多次请求得到的结果一样,就视为请求是幂等的).
・GET 可以被缓存,POST 不能被缓存. (这一点也是承接幂等性).
②
• 关于语义: GET完全可以用于提交数据, POST也完全可以用于获取数据.
• 关于幂等性: 标准建议GET实现为幂等的. 实际开发中GET也不必完全遵守这个规则(主流网站都有"猜你喜欢"功能, 会根据用户的历史行为实时更新现有的结果.
• 关于安全性: 有些资料上说"POST比GET请安全". 这样的说法是不科学的. 是否安全取决于前端在传输密码等敏感信息时是否进行加密, 和GET POST无关.
• 关于传输数据量: 有的资料上说"GET传输的数据量小, POST传输数据量大". 这个也是不科学的, 标准没有规定GET的URL的长度, 也没有规定POST的body的长度. 传输数据量多少, 完全取决于不同浏览器和不同服务器之间的实现区别.
• 关于传输数据类型: 有的资料上说"GET只能传输文本数据, POST可以传输二进制数据". 这个也是不科学的. GET的query string虽然无法直接传输二进制数据, 但是可以针对二进制数据进行url encode.
(3)其他方法:
• PUT与POST相似,只是具有幂等特性,一般用于更新
• DELETE删除服务器指定资源
• OPTIONS返回服务器所支持的请求方法
• HEAD类似于GET,只不过响应体不返回,只返回响应头
• TRACE回显服务器端收到的请求,测试的时候会用到这个
• CONNECT预留,暂无使用
这些方法的HTTP请求可以使用ajax来构造
++请求"报头"(请求头)(header)++
请求头就是 HTTP 请求中,紧跟在第一行后面的一堆 "键值对" 信息,它是给服务器看的 "附加说明书"。
"它就像是你寄快递时,贴在包裹上的快递单"
- 第一行(请求行)是:去哪里(POST /api/login HTTP/1.1)
- 请求头 是:用什么寄、身份是谁、要干什么(Host、Content-Type、Cookie 等)
- 空行是:快递单结束,里面是包裹
- Body(请求体)是:真正的包裹内容(用户提交的账号密码等)
请求头常见类型:
1. 通用类(最基础)
- Host:访问哪个域名(HTTP/1.1 必须有)
- User-Agent:你是什么浏览器 / 设备
- Accept:你能接收什么类型内容(图片、文本等)
- Connection:是否长连接 Keep-Alive
2. 缓存控制类
- Cache-Control:要不要缓存、缓存多久
- Pragma:老版本的 no-cache
- If-Modified-Since:问服务器文件有没有更新
3. 身份 / 状态类
- Cookie:浏览器带给服务器的身份信息
- Authorization:登录令牌(账号密码类)
4. 内容类型类
- Content-Type:发送的数据是什么格式(JSON / 表单)
- Content-Length:数据长度(GET 一般没有,POST 才有)
5. 来源 / 安全类
- Referer:从哪个页面跳过来的
- Origin:跨域时用,表明来自哪个域名
- Upgrade-Insecure-Requests:要求升级成 HTTPS
其中Cookie详细介绍一下:
Cookie 就是服务器塞在你浏览器里的 "小型身份身份证"。
它的核心作用是:让服务器记住 "你是谁",从而解决 HTTP 协议 "无状态" 的问题。
本质是浏览器存储在你本地的一小段文本数据 ,格式是键值对
抓包实拍(最直观)
服务器种下 Cookie(响应头)
HTTP/1.1 200 OK Set-Cookie: sessionId=abc123456; Path=/; HttpOnly <-- 这里就是在种 Cookie Content-Type: text/html你下次访问时带上它(请求头)
GET /user/profile HTTP/1.1 Host: www.example.com Cookie: sessionId=abc123456 <-- 这里就是带上了 Cookie
++"正⽂"(body)++
body 就是 HTTP 请求里的「正文 / 内容」
只有POST、PUT、PATCH这类提交数据的请求才有 body
举个最直观的例子(抓包看到的样子)
POST /login HTTP/1.1
Host: www.xxx.com
Content-Type: application/json
Content-Length: 40
{
"username": "admin",
"password": "123456"
}
- 上面几行是请求头
- 空行下面的这一大段 JSON,就是 body
注意如果不是 JSON 格式比如表单格式,body 长这样:
username=admin&password=123456
这里就没有 { }。
登录和用户认证:
1. 第一次访问网站(还没登录)
你打开浏览器访问网站
- 浏览器发请求
- 服务器:不认识你
- 结果:你是游客状态
2. 你输入账号密码,点登录(发 POST 请求)
浏览器发送一个 POST 请求,body 里带账号密码:
username=zhangsan&password=123456
服务器验证通过后,在响应头里给你种下 Cookie:
Set-Cookie: userId=1001; Path=/; HttpOnly
这一步就是:服务器给你发了一张 "身份证",让浏览器存起来。
3. 浏览器自动保存这个 Cookie
以后只要访问这个网站,浏览器都会自动在请求头里带上:
Cookie: userId=1001
你不用写代码,浏览器自己干。
4. 后续访问任何页面(服务器看 Cookie 认人)
你点 "个人中心""我的订单"......浏览器自动发:
GET /user/profile HTTP/1.1
Host: xxx.com
Cookie: userId=1001
服务器一看 Cookie:
哦,是 userId=1001,是张三,已经登录了。
于是返回你的个人信息。
Session 是服务器上给每个用户单独开的 "小储物柜"
Cookie 是你手里的储物柜钥匙。
它们俩的关系(最核心)
- Cookie :存在浏览器 里,存的是一串随机字符串(叫
sessionId)- Session :存在服务器里,是一块内存 / 数据,存真正的用户信息(用户名、登录状态、权限......)
流程就是:
- 你登录 → 服务器创建一个 Session,把你的信息存进去
- 服务器把这个 Session 的编号
sessionId通过 Cookie 发给浏览器- 以后你每次访问,浏览器自动带 Cookie(钥匙)
- 服务器用这个
sessionId找到对应的 Session(储物柜),认出你是谁过期问题
- Session 也会过期 :
- 太久不操作(比如 30 分钟)
- 服务器重启
- 手动退出登录
- Session 一过期,对应的 Cookie 也就没用了,需要重新登录。