1. 计算机网络基础

1.1 TCP/IP 基础

什么是 TCP/IP?

TCP/IP 是互联网通信的 协议族,它定义了数据如何在网络中传输。TCP 和 IP 是其中最核心的两个协议:

  • IP(Internet Protocol):负责将数据包从一台计算机发送到另一台计算机,它只关心“如何到达”,但不保证数据是否丢失或顺序正确。
  • TCP(Transmission Control Protocol):建立在 IP 之上,提供可靠的、面向连接的通信。它会确保数据包按顺序到达、没有丢失,如果丢失就重传。

三次握手(建立连接)

当客户端(如浏览器)想和服务器建立 TCP 连接时,会进行 三次握手

  1. 客户端 → 服务器:发送一个 SYN(同步)包,表示“我想跟你建立连接”。
  2. 服务器 → 客户端:回复 SYN-ACK 包,表示“我收到了你的请求,并且我也同意建立连接”。
  3. 客户端 → 服务器:发送 ACK 包,表示“好的,连接建立成功”。

为什么是三次?
确保双方的收发能力都正常。第一次握手证明客户端能发,第二次证明服务器能收也能发,第三次证明客户端能收。如果只有两次,服务器无法确认客户端是否收到了自己的确认包。

四次挥手(断开连接)

当通信结束时,需要 四次挥手 断开连接:

  1. 客户端 → 服务器:发送 FIN 包,表示“我要关闭连接了”。
  2. 服务器 → 客户端:回复 ACK 包,表示“我收到了你的关闭请求”。
  3. 服务器 → 客户端:发送 FIN 包,表示“我也准备关闭了”。
  4. 客户端 → 服务器:回复 ACK 包,表示“好的,可以关闭了”。

为什么是四次?
因为 TCP 连接是 全双工 的,双方都可以独立地关闭自己的通道。客户端发送 FIN 表示自己不再发送数据,但服务器可能还有数据要发,所以服务器先回复 ACK 确认,然后等自己的数据发完再发 FIN。所以多了一步。

TCP 与 UDP 的区别

特性 TCP UDP
连接 面向连接(三次握手) 无连接
可靠性 可靠传输(确认、重传、顺序) 不可靠,可能丢包、乱序
速度 较慢,因为要保证可靠性 较快,没有额外开销
应用场景 HTTP、FTP、邮件等需要可靠传输的场景 视频直播、DNS、游戏等允许丢包的场景

一句话总结:网络协议就是计算机之间的“通信规则”,TCP 保证数据不丢,UDP 追求速度。


1.2 DNS 解析:域名如何变成 IP

当你在浏览器输入 www.example.com 时,计算机需要知道这个域名对应的 IP 地址才能建立连接。这个过程叫 DNS 解析,大致流程如下:

  1. 浏览器缓存:先检查浏览器是否缓存了该域名的 IP。
  2. 操作系统缓存:如果浏览器没有,就检查操作系统的 hosts 文件或 DNS 缓存。
  3. 本地 DNS 服务器:如果操作系统也没有,就向配置的本地 DNS 服务器(如路由器或 ISP 提供的)发起请求。
  4. 递归查询:本地 DNS 服务器会代表客户端向根域名服务器、顶级域名服务器(如 .com)、权威域名服务器依次查询,最终获得 IP。
  5. 返回结果:本地 DNS 服务器将 IP 返回给客户端,并缓存一段时间(TTL)。

简单比喻:DNS 就像电话簿,你只知道对方的名字(域名),通过电话簿查到对方的电话号码(IP)。


1.3 端口

端口 是计算机上用于区分不同网络服务的 逻辑编号,范围 0~65535。当数据包到达计算机时,操作系统根据端口号将数据交给对应的应用程序。

  • 为什么后端服务要监听端口?
    服务器上可能同时运行 Web 服务(监听 80)、数据库(监听 3306)等,通过端口号区分不同服务。客户端必须指定端口才能与正确的服务通信。

常见端口号

  • 80:HTTP(默认)
  • 443:HTTPS
  • 3306:MySQL 数据库
  • 6379:Redis 缓存
  • 8000:常用于开发测试(如 Django 开发服务器)

2. HTTP 协议详解

HTTP(HyperText Transfer Protocol)是浏览器和服务器之间通信的 协议,它定义了请求和响应的格式。

一句话总结:HTTP 就是浏览器和服务器之间的“对话格式”——请求怎么写、响应怎么回、状态码代表什么意思。

2.1 请求方法

HTTP 定义了多种 请求方法,表示对资源要执行的操作:

方法 语义 说明
GET 获取资源 只请求数据,不修改资源,幂等(多次请求结果相同)
POST 提交数据(创建资源) 常用于表单提交、上传文件,非幂等
PUT 更新资源(全量替换) 将整个资源替换为请求体内容,幂等
PATCH 部分更新资源 只修改资源的部分字段,幂等
DELETE 删除资源 幂等

注意:虽然 GET 也可以携带数据(通过 URL 参数),但通常不建议用 GET 发送敏感信息,因为 URL 会被记录在日志中。

2.2 状态码

服务器响应的状态码表示请求的处理结果,分为五类:

  • 1xx:信息性(如 100 Continue)
  • 2xx:成功
    • 200 OK:请求成功
    • 201 Created:资源创建成功(常用于 POST)
    • 204 No Content:请求成功,但无返回内容(如 DELETE 成功)
  • 3xx:重定向
    • 301 Moved Permanently:永久重定向
    • 302 Found:临时重定向
  • 4xx:客户端错误
    • 400 Bad Request:请求格式错误
    • 401 Unauthorized:未认证(需要登录)
    • 403 Forbidden:禁止访问(即使认证了也无权限)
    • 404 Not Found:资源不存在
  • 5xx:服务器错误
    • 500 Internal Server Error:服务器内部错误
    • 502 Bad Gateway:网关错误
    • 503 Service Unavailable:服务不可用(如过载)

2.3 请求和响应结构

HTTP 请求

一个典型的 HTTP 请求包含:

GET /users/123 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
  • 请求行:方法 + 路径 + HTTP 版本
  • 请求头:键值对,包含额外信息(如 Host、User-Agent、Content-Type)
  • 空行:分隔头部和主体
  • 请求体:可选,用于 POST、PUT 等携带数据

HTTP 响应

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123

{"id": 123, "name": "Alice"}
  • 状态行:HTTP 版本 + 状态码 + 状态短语
  • 响应头:键值对
  • 空行
  • 响应体:返回的数据

2.4 Content-Type

Content-Type 头部告诉接收方数据的格式,常见的有:

  • application/json:JSON 格式数据
  • application/x-www-form-urlencoded:表单数据(键值对,如 name=Alice&age=25
  • multipart/form-data:用于文件上传(每个部分用 boundary 分隔)
  • text/html:HTML 文档
  • text/plain:纯文本

HTTP 是 无状态 协议,即服务器默认不会记住之前的请求。但 Web 应用需要记住用户登录状态,于是引入了 Cookie 和 Session。

  • Cookie:浏览器保存的小段文本,由服务器通过 Set-Cookie 头部发送给浏览器,浏览器后续请求会自动带上。通常用来存储 session ID。
  • Session:服务器端存储的用户数据,通过 session ID 关联。用户登录后,服务器创建 session,并将 session ID 通过 Cookie 发给客户端。

工作流程

  1. 用户登录 → 服务器验证身份,创建 session,生成 session ID。
  2. 服务器在响应头中设置 Set-Cookie: sessionid=abc123
  3. 浏览器保存该 Cookie,后续请求自动在 Cookie 头部携带 sessionid=abc123
  4. 服务器根据 session ID 找到对应的 session 数据,从而识别用户。

2.6 HTTPS

HTTPS = HTTP + SSL/TLS,它在 HTTP 和 TCP 之间加了一层加密层,保证数据传输的 机密性、完整性、身份验证

基本流程

  1. 客户端请求服务器证书(公钥)。
  2. 服务器返回证书(包含公钥和签名)。
  3. 客户端验证证书的合法性(是否由可信 CA 签发,域名是否匹配)。
  4. 客户端生成一个对称加密密钥,用服务器的公钥加密后发送给服务器。
  5. 双方使用这个对称密钥进行加密通信。

为什么比 HTTP 安全?

  • HTTP 传输是明文,容易被窃听、篡改。
  • HTTPS 加密后,即使数据被截获也无法解密,且通过证书防止中间人攻击。

2.7 CORS(跨域资源共享)

什么是跨域?
当浏览器向不同源(协议、域名、端口任一不同)的服务器发送请求时,就产生了跨域。浏览器出于安全考虑,限制脚本发起的跨域 HTTP 请求(除非服务器明确允许)。

为什么会有跨域限制?
防止恶意网站通过脚本访问其他网站的数据(如从 A 网站向 B 银行网站发送请求获取用户信息)。这是浏览器的同源策略。

如何解决?
服务器需要在响应头中加入 CORS 相关头部,告诉浏览器允许跨域:

  • Access-Control-Allow-Origin: *(允许所有域,或指定具体域名)
  • Access-Control-Allow-Methods: GET, POST, PUT(允许的请求方法)
  • Access-Control-Allow-Headers: Content-Type(允许的自定义头部)

对于复杂请求(如 PUT、DELETE 或带自定义头),浏览器会先发送一个 OPTIONS 预检请求,确认服务器允许后才会发送实际请求。


3. RESTful API 设计规范

RESTful 是一种 API 设计风格,它利用 HTTP 协议的特性,使 API 更加清晰、易于理解。

一句话总结:RESTful 就是一套“怎么设计好用的 API”的约定。

3.1 URL 设计

  • 使用 名词复数 表示资源集合,例如 /users 表示所有用户,/users/123 表示特定用户。
  • 资源层级用 / 表示,例如 /users/123/orders 表示用户 123 的订单列表。
  • 避免在 URL 中使用动词,操作由 HTTP 方法表达。

3.2 HTTP 方法对应 CRUD

操作 HTTP 方法 URL 说明
创建 POST /users 创建新用户
读取 GET /users 获取用户列表
读取 GET /users/123 获取用户 123 的详细信息
全量更新 PUT /users/123 替换用户 123 的全部信息
部分更新 PATCH /users/123 更新用户 123 的部分字段
删除 DELETE /users/123 删除用户 123

3.3 统一响应格式

建议返回统一的 JSON 结构,包含状态码、消息和数据,方便前端统一处理:

{
  "code": 200,
  "message": "success",
  "data": { "id": 123, "name": "Alice" }
}

或者使用 HTTP 状态码表示结果,data 直接放资源(但需要处理错误时格式一致)。

3.4 分页、排序、过滤、搜索

  • 分页:使用 pagepage_size 参数,如 GET /users?page=2&page_size=20,响应中返回总条数、当前页数据。
  • 排序sort 参数,如 GET /users?sort=name,-created_at(+表示升序,-表示降序)。
  • 过滤:用字段名作为参数,如 GET /users?age=25&city=Beijing
  • 搜索:用 qsearch 参数,如 GET /users?q=alice

3.5 API 版本管理

当 API 发生不兼容更新时,需要版本管理。常见方式:

  • URL 路径:/api/v1/users/api/v2/users
  • 请求头:Accept: application/vnd.myapp.v1+json
  • 参数:/users?version=1

最简单且常用的方式是在 URL 中包含版本号。


4. 认证与授权基础

认证(Authentication):验证你是谁(比如登录)。
授权(Authorization):确定你能做什么(比如普通用户不能删除其他用户)。

4.1 Session 与 Token

特性 Session Token(如 JWT)
存储位置 服务器存储 session 数据,客户端只存 session ID 客户端存储 token,服务器不存储(或仅验证)
状态 有状态(服务器需要记录 session) 无状态(服务器通过 token 自身携带的信息验证)
扩展性 在分布式环境中需要共享 session(如 Redis) 天然适合分布式,token 自包含
缺点 占用服务器内存,扩展复杂 token 一旦签发,难以吊销(除非加黑名单)

Session 流程

  1. 登录成功 → 服务器创建 session,返回 session ID(通过 Cookie)。
  2. 后续请求携带 Cookie → 服务器根据 session ID 查找 session。

Token 流程

  1. 登录成功 → 服务器生成 token(如 JWT)返回给客户端。
  2. 客户端在后续请求的 Authorization 头中携带 Bearer <token>
  3. 服务器验证 token 签名,解析出用户信息,无需查询 session。

4.2 JWT(JSON Web Token)

JWT 是一种常用的 token 格式,它由三部分组成,用点分隔:

header.payload.signature
  • Header:包含类型(JWT)和签名算法(如 HS256)。
  • Payload:包含用户自定义的数据(如 user_id、过期时间 exp)。
  • Signature:对前两部分进行签名,防止篡改。

示例

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

生成和验证

  • 服务器使用密钥(对称算法)或私钥(非对称)对 header 和 payload 进行签名。
  • 验证时,服务器用同样的密钥或公钥重新计算签名,比对是否一致,并检查过期时间。

一句话总结:JWT 是一种自包含的 token,服务器不需要存储 session,只需验证签名即可信任其中的数据。

4.3 OAuth 2.0(第三方登录)

OAuth 2.0 是一种授权协议,允许用户授权第三方应用访问自己在某个服务上的资源(比如用 GitHub 账号登录你的网站)。最常见的流程是 授权码模式(以 GitHub 登录为例):

  1. 用户在你的网站点击“使用 GitHub 登录”,跳转到 GitHub 授权页面。
  2. 用户同意授权后,GitHub 重定向回你的网站,并携带一个 授权码
  3. 你的后端服务器使用授权码向 GitHub 请求 访问令牌(access token)。
  4. 拿到访问令牌后,可以用它调用 GitHub API 获取用户信息(如用户名、邮箱)。
  5. 根据获取的信息,在你的系统中创建或登录用户。

注意:OAuth 2.0 的核心是授权,不是认证。但它常被用来实现第三方登录(通过授权获取用户信息来认证)。

4.4 密码安全

  • 绝对不要明文存储密码!一旦数据库泄露,用户密码就暴露了。
  • 应该存储 密码的哈希值,哈希是单向函数,无法从哈希值还原密码。
  • 使用 加盐哈希:对每个用户生成随机盐,与密码拼接后哈希,防止彩虹表攻击。
  • 推荐使用 bcryptargon2 等专门为密码设计的哈希算法,它们自动处理盐和迭代次数,且计算缓慢,可以抵御暴力破解。

示例(Python bcrypt)

import bcrypt

# 哈希密码
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(b"my_password", salt)

# 验证密码
if bcrypt.checkpw(b"my_password", hashed):
    print("密码正确")

一句话总结:认证 = “你是谁”,授权 = “你能干什么”。千万不要自己“发明”加密算法,用成熟的库(bcrypt、passlib)就对了。


5. 练习

5.1 使用 curl 或 Postman 观察 HTTP 细节

curl 是命令行工具,可以发送各种 HTTP 请求。试着执行以下命令,观察输出:

# 发送 GET 请求,显示响应头和响应体
curl -v https://api.github.com/users/octocat

# 发送 POST 请求,携带 JSON 数据
curl -X POST -H "Content-Type: application/json" -d '{"name":"Alice"}' http://httpbin.org/post

Postman 是图形化工具,可以更方便地构建请求、查看头部和响应。尝试创建一个请求,观察请求头、响应头、状态码。

5.2 用 Python 的 http.server 写一个最简单的 HTTP 服务器

Python 内置了 http.server 模块,可以快速启动一个静态文件服务器,也可以自定义处理逻辑。

例子 1:启动静态服务器

python -m http.server 8000

访问 http://localhost:8000,可以看到当前目录的文件列表。

例子 2:自定义请求处理

from http.server import HTTPServer, BaseHTTPRequestHandler

class SimpleHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()
        self.wfile.write(b'Hello, World!')
    
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length)
        print("Received POST data:", post_data)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'POST received')

server = HTTPServer(('localhost', 8000), SimpleHandler)
print("Server running on http://localhost:8000")
server.serve_forever()

运行后,用 curl 测试:

curl -v http://localhost:8000
curl -X POST -d "hello" http://localhost:8000

观察请求和响应的完整过程。

5.3 画一张 HTTP 请求的完整流程图

结合本章知识,画一张从用户在浏览器输入 URL 到看到页面的流程图,包含以下环节:

  • DNS 解析
  • TCP 三次握手
  • 发送 HTTP 请求
  • 服务器处理请求
  • 返回 HTTP 响应
  • TCP 四次挥手
  • 浏览器渲染页面

你可以用纸笔画,也可以用流程图工具。这有助于将零散的知识串联起来。


6. 总结

  • 计算机网络 让你明白数据是如何在互联网上传输的,三次握手和四次挥手是面试常考的重点。
  • HTTP 协议 是浏览器与服务器对话的语言,请求方法、状态码、头部、Cookie/Session、HTTPS、CORS 都是日常开发中频繁打交道的知识点。
  • RESTful 设计规范 提供了一套优雅的 API 设计思路,让前后端协作更顺畅。
  • 认证与授权 保障了 Web 应用的安全性,Session、JWT、OAuth 2.0 和密码哈希是构建用户系统的基石。