1. 终章:连接一切的桥梁

兄弟们,恭喜你走到了这里!这是《Python 从零到精通》系列的最后一讲。

在前面的课程里,我们学会了写逻辑、存数据、做 Web。但这些东西是怎么在互联网上飞来飞去的?为什么你输入 google.com 就能看到网页?

这一讲,我们要揭开网络协议的神秘面纱,并聊聊如何设计出让前端同学感激涕零的 RESTful API


2. TCP/IP 协议栈详解

在深入讨论 HTTP 之前,我们需要先理解它的根基——TCP/IP 协议栈。这是一套分层网络通信模型,是现代互联网的基石。

2.1 四层模型概览

TCP/IP 协议栈分为四层,每一层各司其职:

层级 名称 核心功能 典型协议/设备
第4层 应用层 为应用程序提供网络服务 HTTP、FTP、SMTP、DNS
第3层 传输层 端到端的数据传输控制 TCP、UDP
第2层 网络层 寻址和路由选择 IP、ICMP、路由器
第1层 网络接口层 物理数据传输 以太网、WiFi、网卡

数据封装过程:当数据从应用层向下传递时,每一层都会添加自己的头部信息(封装),到达目标主机后再逐层解封。

2.2 网络层:IP 协议

IP(互联网协议) 负责将数据包从源地址传送到目标地址。

IPv4 vs IPv6

特性 IPv4 IPv6
地址长度 32位(约42亿个地址) 128位(约340涧个地址)
地址格式 192.168.1.1 2001:0db8:85a3::8a2e:0370:7334
安全性 可选IPSec 内置IPSec
现状 地址枯竭,逐步过渡 未来主流

2.3 传输层:TCP 与 UDP

在聊 HTTP 之前,我们必须先了解它的底层——传输层协议。TCP 和 UDP 是互联网传输数据的两种方式,各有千秋。

2.3.1 TCP:可靠的老实人

TCP(传输控制协议) 就像一个负责任的快递员,必须确认你签收了才算送达。

核心特点

  • 三次握手:建立连接时,客户端和服务端要来回确认三次
    • 第一次:客户端发送 SYN(请求建立连接)
    • 第二次:服务端回复 SYN+ACK(确认收到,同意建立)
    • 第三次:客户端发送 ACK(确认建立连接)
  • 四次挥手:断开连接时,也要确认四次
    • 确保双方数据都传输完毕才关闭
  • 可靠传输:数据丢失会自动重传,保证数据完整
  • 有序到达:数据包按顺序重组,不会乱序
  • 流量控制:通过滑动窗口机制防止发送方淹没接收方
  • 拥塞控制:根据网络状况动态调整发送速率

适用场景:网页浏览、文件传输、邮件发送——凡是不能丢数据的场景。

2.3.2 UDP:潇洒的急先锋

UDP(用户数据报协议) 就像寄明信片,扔出去就不管了,能不能收到看缘分。

核心特点

  • 无连接:不需要建立连接,直接发
  • 不可靠:数据丢了就丢了,不重传
  • 速度快:没有确认机制,延迟极低
  • 无序:数据包可能乱序到达
  • 头部开销小:仅8字节,TCP需要20字节

适用场景:视频直播、语音通话、在线游戏——宁可丢几帧,也不能卡顿。

2.4 TCP vs UDP 对比表

特性 TCP UDP
连接方式 面向连接 无连接
可靠性 高,保证送达 低,可能丢包
速度 较慢
有序性 保证顺序 不保证
头部大小 20字节 8字节
拥塞控制
典型应用 HTTP、FTP、SMTP DNS、视频直播、游戏

一句话总结:TCP 稳但慢,UDP 快但野。选谁取决于你的业务需求。


3. HTTP:互联网的"通用语言"

所有的 Web 开发,本质上都是在玩 HTTP。

3.1 HTTP 版本演进:1.1 vs 2 vs 3

HTTP 协议经历了多次重大升级,每个版本都解决了前代的痛点:

3.1.1 HTTP/1.1(1997年)

特点

  • 持久连接(Keep-Alive):复用 TCP 连接,减少握手开销
  • 管道化(Pipelining):允许连续发送多个请求,无需等待响应
  • 分块传输编码:支持流式传输大文件
  • 缓存控制:引入 Cache-Control 等头部

痛点

  • 队头阻塞(Head-of-Line Blocking):一个请求阻塞,后续请求都得等
  • 每个请求都需要完整的 HTTP 头部,冗余传输
  • 同一域名下浏览器限制6-8个并发连接
3.1.2 HTTP/2(2015年)

核心改进

特性 说明 优势
二进制分帧 数据以二进制帧传输,而非文本 解析更高效,错误更少
多路复用 单一 TCP 连接上并行传输多个请求 彻底解决队头阻塞
头部压缩 HPACK 算法压缩请求头 减少冗余数据传输
服务器推送 服务端主动推送资源 提前加载关键资源
流优先级 设置请求优先级 关键资源优先加载

一句话总结:HTTP/2 让网页加载速度大幅提升,是现代 Web 的主流选择。

3.1.3 HTTP/3(2022年)

革命性变化:基于 QUIC 协议(基于 UDP),而非 TCP。

核心优势

  • 零 RTT 连接:首次连接只需1个 RTT,重连时0 RTT
  • 彻底解决队头阻塞:QUIC 在传输层解决,单个流阻塞不影响其他流
  • 连接迁移:网络切换(WiFi转4G)时连接不中断
  • 内置加密:TLS 1.3 集成,握手更快

适用场景:移动应用、实时通信、对延迟敏感的应用。

3.1.4 版本对比总结
特性 HTTP/1.1 HTTP/2 HTTP/3
传输层 TCP TCP QUIC (UDP)
队头阻塞 应用层解决 彻底解决
多路复用
头部压缩 HPACK QPACK
服务器推送
连接建立 2-3 RTT 2-3 RTT 0-1 RTT
连接迁移 不支持 不支持 支持

3.2 请求 (Request) 与响应 (Response)

  • 请求:你跟服务器说:“给我看一眼那张图片。”
  • 响应:服务器说:"行,给你。“或者"对不起,没找到。”

一个 HTTP 请求由三部分组成:请求行、请求头、请求体。响应也是类似的结构。

3.3 常见的 HTTP 方法(四大天王)

方法 用途 是否有请求体 是否幂等
GET 查询资源
POST 创建资源
PUT 更新资源(全量)
DELETE 删除资源 可选
PATCH 更新资源(部分)

幂等性解释:同一个请求执行一次和执行多次,效果相同。GET、PUT、DELETE 是幂等的,POST 不是。

3.4 状态码:服务器的"微表情"

状态码 类别 含义 常见示例
2xx 成功 请求被成功处理 200 OK, 201 Created
3xx 重定向 需要进一步操作 301 永久移动, 302 临时移动
4xx 客户端错误 请求有问题 400 Bad Request, 404 Not Found
5xx 服务端错误 服务器出问题了 500 Internal Error, 502 Bad Gateway

4. HTTP 缓存机制:让网站飞起来

每次请求都从服务器拉数据太慢了。HTTP 缓存让浏览器把资源存下来,下次直接用。

4.1 强缓存:不问服务器,直接用

强缓存期间,浏览器根本不发请求,直接用本地缓存。

关键响应头

响应头 说明 示例
Cache-Control 缓存控制(HTTP/1.1) max-age=3600
Expires 过期时间(HTTP/1.0,已过时) Wed, 21 Oct 2026 07:28:00 GMT

Cache-Control 常用指令

  • max-age=3600:缓存 3600 秒
  • no-cache:每次使用前要验证(不是不缓存!)
  • no-store:完全不缓存
  • public:可以被任何缓存(包括 CDN)存储
  • private:只能被浏览器缓存

4.2 协商缓存:问一下服务器,能不能用

强缓存过期后,浏览器会问服务器:“我这里有个缓存,还能用吗?”

两种验证方式

方式 请求头 响应头 原理
Last-Modified If-Modified-Since Last-Modified 比较修改时间
ETag If-None-Match ETag 比较内容哈希值

ETag 更精确:因为文件可能内容没变但修改时间变了,或者修改时间没变但内容变了。

协商缓存命中时:服务器返回 304 Not Modified,不返回内容,省带宽。


5. RESTful API 设计深度解析

全栈开发里,后端和前端的沟通就靠 API。如果你乱写,前端同学可能会拿着键盘找你拼命。

5.1 REST 架构核心原则

REST(Representational State Transfer)是一种软件架构风格,由 Roy Fielding 在2000年提出。

5.1.1 资源(Resources)

REST 的核心是资源,任何可以命名的事物都可以是资源:用户、订单、文章、图片等。

  • 错误示范/get_all_users, /delete_user_by_id?id=1(动作导向)
  • 正确示范GET /users, DELETE /users/1(名词导向)
5.1.2 统一接口(Uniform Interface)
原则 说明 实践
资源标识 每个资源有唯一标识符 URL 作为资源标识
自描述消息 请求包含足够信息 使用标准 HTTP 方法和头部
资源的自描述 响应包含资源表示 JSON/XML 表示资源状态
HATEOAS 超媒体作为应用状态引擎 响应中包含相关资源链接
5.1.3 无状态(Stateless)

服务器不保存客户端的上下文状态。每个请求都必须包含所有必要信息。

好处

  • 服务端容易扩展(任意服务器实例都可以处理请求)
  • 请求可以被缓存
  • 系统更可靠(没有会话状态丢失的问题)

5.2 RESTful 风格要点

  1. URL 用名词,不用动词
  2. HTTP 方法表达操作类型
  3. 资源用复数形式/users 而非 /user
  4. 层级关系用路径表达/users/1/orders

5.3 状态码使用规范

场景 状态码 说明
查询成功 200 OK 返回资源列表或详情
创建成功 201 Created 返回新创建的资源
删除成功 204 No Content 无需返回内容
参数错误 400 Bad Request 请求参数校验失败
未认证 401 Unauthorized 缺少或无效的认证信息
无权限 403 Forbidden 已认证但无权访问
资源不存在 404 Not Found URL 对应的资源不存在
资源冲突 409 Conflict 如重复创建已存在资源
服务器错误 500 Internal Server Error 服务端异常

5.4 响应格式标准化

{
    "code": 200,
    "msg": "Success",
    "data": {
        "id": 1,
        "name": "张三"
    },
    "timestamp": 1709012345
}

统一结构的好处:前端可以用同一套逻辑处理所有响应,不用为每个接口写特殊处理。


6. 认证与授权机制

API 的安全性至关重要。我们需要区分认证(你是谁)和授权(你能做什么)。

6.1 JWT(JSON Web Token)

JWT 是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。

6.1.1 JWT 结构

JWT 由三部分组成,用点号分隔:

xxxxx.yyyyy.zzzzz
|     |     |
头部   载荷   签名

头部(Header)

{
    "alg": "HS256",
    "typ": "JWT"
}

载荷(Payload)

{
    "sub": "1234567890",
    "name": "张三",
    "iat": 1516239022,
    "exp": 1516242622
}

签名(Signature)

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)
6.1.2 JWT 工作流程
  1. 用户登录,服务端验证成功后生成 JWT
  2. 服务端将 JWT 返回给客户端
  3. 客户端将 JWT 存储(LocalStorage 或 Cookie)
  4. 后续请求携带 JWT(通常放在 Authorization 头部)
  5. 服务端验证 JWT 签名和有效期
6.1.3 JWT Python 实现
import jwt
from datetime import datetime, timedelta, timezone

# 生成 JWT
def create_token(user_id: str, secret: str, expires_hours: int = 24):
    now = datetime.now(timezone.utc)
    payload = {
        "user_id": user_id,
        "exp": now + timedelta(hours=expires_hours),
        "iat": now
    }
    token = jwt.encode(payload, secret, algorithm="HS256")
    return token

# 验证 JWT
def verify_token(token: str, secret: str):
    try:
        payload = jwt.decode(token, secret, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        return None  # Token 过期
    except jwt.InvalidTokenError:
        return None  # Token 无效

# 使用示例
secret_key = "your-secret-key-must-be-at-least-32-bytes-long"
token = create_token("user_123", secret_key)
print(f"生成的 Token: {token}")

payload = verify_token(token, secret_key)
print(f"验证结果: {payload}")
6.1.4 JWT 最佳实践
建议 说明
设置合理的过期时间 建议访问令牌15分钟,刷新令牌7天
使用 HTTPS 防止 Token 被截获
不要在 JWT 中存放敏感信息 Payload 只是 Base64 编码,可被解码
使用强密钥 至少256位的密钥
实现 Token 黑名单 用于登出等场景

6.2 OAuth 2.0

OAuth 2.0 是一种授权框架,允许第三方应用获取用户资源的有限访问权限,而不暴露用户密码。

6.2.1 核心角色
角色 说明 示例
资源所有者 拥有资源的用户 微信用户
客户端 请求访问资源的应用 某第三方网站
授权服务器 验证用户身份并颁发令牌 微信授权服务器
资源服务器 托管受保护资源的服务器 微信用户信息接口
6.2.2 授权流程(授权码模式)
+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+
6.2.3 FastAPI 集成 OAuth2
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel

app = FastAPI()

# Token URL
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# 模拟用户数据库
fake_users_db = {
    "zhangsan": {
        "username": "zhangsan",
        "password": "secret_password",
        "disabled": False
    }
}

class User(BaseModel):
    username: str
    disabled: bool = False

def get_user(db, username: str):
    if username in db:
        return User(**db[username])
    return None

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # 实际项目中这里需要验证 JWT
    user = get_user(fake_users_db, token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"}
        )
    return user

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or user["password"] != form_data.password:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password"
        )
    return {"access_token": user["username"], "token_type": "bearer"}

@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

6.3 JWT vs OAuth2 对比

特性 JWT OAuth2
定位 Token 格式标准 授权框架
用途 携带用户身份信息 第三方授权访问
复杂度 简单 较复杂
适用场景 单应用认证 第三方登录、API 开放平台
关系 OAuth2 可以使用 JWT 作为 Token 格式 OAuth2 是框架,JWT 是工具

7. API 版本控制策略

你的 API 以后肯定会升级。为了不让旧版本的前端崩掉,需要设计好版本控制策略。

7.1 为什么需要版本控制

  • 功能迭代:新增功能可能改变响应结构
  • 字段变更:删除或修改字段会破坏旧客户端
  • Bug 修复:修复可能改变原有行为
  • 性能优化:查询参数或路径可能调整

7.2 版本控制策略

7.2.1 URL 路径版本(推荐)
https://api.myapp.com/v1/users
https://api.myapp.com/v2/users

优点

  • 直观清晰,一眼看出版本
  • 易于缓存和路由
  • 适合重大版本变更

缺点

  • URL 变更可能影响书签和文档
7.2.2 查询参数版本
https://api.myapp.com/users?version=1
https://api.myapp.com/users?version=2

优点

  • URL 结构保持稳定
  • 适合小版本变更

缺点

  • 不够直观
  • 可能被缓存策略忽略
7.2.3 请求头版本
Accept: application/vnd.myapp.v1+json
Accept-Version: v1

优点

  • URL 保持干净
  • 符合 REST 纯化论

缺点

  • 不够直观,调试困难
  • 需要额外的文档说明

7.3 FastAPI 实现 API 版本控制

from fastapi import FastAPI, APIRouter
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI()

# v1 模型
class UserV1(BaseModel):
    id: int
    name: str
    email: str

# v2 模型(新增字段)
class UserV2(BaseModel):
    id: int
    name: str
    email: str
    avatar: Optional[str] = None
    created_at: Optional[str] = None

# v1 路由
v1_router = APIRouter(prefix="/v1")

@v1_router.get("/users", response_model=List[UserV1])
async def get_users_v1():
    return [
        {"id": 1, "name": "张三", "email": "zhangsan@example.com"}
    ]

# v2 路由
v2_router = APIRouter(prefix="/v2")

@v2_router.get("/users", response_model=List[UserV2])
async def get_users_v2():
    return [
        {
            "id": 1, 
            "name": "张三", 
            "email": "zhangsan@example.com",
            "avatar": "https://example.com/avatar.jpg",
            "created_at": "2024-01-01T00:00:00Z"
        }
    ]

# 注册路由
app.include_router(v1_router)
app.include_router(v2_router)

@app.get("/")
async def root():
    return {
        "message": "API Versioning Demo",
        "versions": ["v1", "v2"]
    }

7.4 版本控制最佳实践

建议 说明
从 v1 开始 不要从无版本开始,预留扩展空间
向后兼容 尽量保持旧版本稳定运行
弃用通知 弃用旧版本前提前通知客户端
版本生命周期 制定明确的版本支持周期
文档同步 每个版本都要有对应的文档

8. 跨域问题(CORS):前后端分离的拦路虎

当前端和后端不在同一个域名下,浏览器会拦截请求,这就是跨域

8.1 为什么会有跨域?

浏览器的同源策略(Same-Origin Policy)限制了从一个源加载的文档或脚本如何与另一个源的资源交互。

同源的定义:协议、域名、端口完全相同。

URL A URL B 是否同源 原因
http://a.com/page http://a.com/api 完全相同
http://a.com/page https://a.com/api 协议不同
http://a.com/page http://api.a.com/data 域名不同
http://a.com/page http://a.com:8080/api 端口不同

8.2 CORS 解决方案

CORS(跨源资源共享) 是 W3C 标准,通过设置响应头让浏览器放行。

关键响应头

响应头 说明 示例
Access-Control-Allow-Origin 允许的源 *https://example.com
Access-Control-Allow-Methods 允许的方法 GET, POST, PUT, DELETE
Access-Control-Allow-Headers 允许的请求头 Content-Type, Authorization
Access-Control-Allow-Credentials 是否允许携带 Cookie true

FastAPI 中启用 CORS

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

9. JSON 格式规范详解

JSON 是前后端数据交换的通用格式,掌握它的规范很重要。

9.1 JSON 数据类型

类型 说明 示例
字符串 必须用双引号 "hello"
数字 整数或浮点数 42, 3.14
布尔值 只有 true/false true, false
空值 只有 null null
对象 键值对集合 {"name": "张三"}
数组 有序值列表 [1, 2, 3]

9.2 JSON 常见陷阱

  1. 键必须用双引号{'name': '张三'} 是错的,必须是 {"name": "张三"}
  2. 最后一个元素后面不能有逗号[1, 2, 3,] 是错的
  3. 不支持注释:JSON 里不能写注释
  4. 不支持单引号:字符串必须用双引号

9.3 Python 处理 JSON

import json

data = {"name": "张三", "age": 25}

json_str = json.dumps(data, ensure_ascii=False, indent=2)

parsed = json.loads(json_str)

10. 全栈项目总结:我们学到了什么?

回顾这 10 讲,你其实已经掌握了一套完整的全栈开发闭环

10.1 知识图谱总览

阶段 讲次 核心技能 实战产出
入门 第1-2讲 环境配置、变量、流程控制 能写简单脚本
进阶 第3讲 函数、模块、装饰器 代码可复用
架构 第4讲 面向对象、设计模式 代码有结构
稳健 第5讲 异常处理、文件 IO 程序不崩溃
高效 第6讲 并发、正则、高级特性 性能优化
持久 第7讲 MySQL、Redis 数据能存
服务 第8讲 FastAPI 能提供接口
工程 第9讲 Git、测试、Docker 团队协作
网络 第10讲 HTTP、API 设计 系统互联

10.2 从零到一的能力矩阵

学完这个系列,你应该能够:

  1. 独立开发:从零搭建一个完整的 Web 项目
  2. 团队协作:用 Git 管理代码,用测试保证质量
  3. 生产部署:用 Docker 容器化,用日志排查问题
  4. 架构设计:理解分层、解耦、设计模式
  5. 持续学习:具备阅读文档、排查问题的能力

11. 避坑小贴士(终章寄语)

  1. 别停止练习:看十遍教程,不如自己亲手写一个项目。去写一个属于你自己的博客系统、爬虫工具或者小游戏。
  2. 读别人的代码:去 GitHub 看看那些优秀的开源项目(比如 FastAPI 源码、Requests 源码),那是最好的进阶教材。
  3. 拥抱 AI,但不依赖 AI:你可以用 ChatGPT 帮你写个小函数,但你必须理解它背后的逻辑,否则你永远无法解决那些深层次的 Bug。
  4. 记录和分享:写技术博客,记录你踩过的坑。教是最好的学。
  5. 关注社区:Python 发展很快,保持对新技术的敏感度。

12. 实战演练:巩固你的内功

题目 1:Requests 爬虫与伪装

需求
使用 requests 模拟发送一个 GET 请求到 https://httpbin.org/get
设置请求头 User-Agent 为 “MyPythonBot/1.0”。
带上查询参数 page=1, limit=10
打印响应的状态码和 JSON 内容。

点击查看参考答案
import requests

url = "https://httpbin.org/get"
headers = {"User-Agent": "MyPythonBot/1.0"}
params = {"page": 1, "limit": 10}

try:
    resp = requests.get(url, headers=headers, params=params, timeout=5)
  
    if resp.status_code == 200:
        print("请求成功!")
        data = resp.json()
        print(f"User-Agent: {data['headers']['User-Agent']}")
        print(f"Args: {data['args']}")
    else:
        print(f"请求失败:{resp.status_code}")
      
except Exception as e:
    print(f"发生错误:{e}")

题目 2:JSON 序列化 (datetime 处理)

需求
有一个字典包含 datetime 对象,直接 json.dumps 会报错。
编写一个自定义的 default 函数,将日期对象转为 “YYYY-MM-DD HH:MM:SS” 格式的字符串。
序列化该字典。

点击查看参考答案
import json
from datetime import datetime

data = {
    "id": 101,
    "title": "测试订单",
    "created_at": datetime.now()
}

def json_encoder(obj):
    if isinstance(obj, datetime):
        return obj.strftime("%Y-%m-%d %H:%M:%S")
    raise TypeError(f"Type {type(obj)} not serializable")

json_str = json.dumps(data, default=json_encoder, indent=4, ensure_ascii=False)
print(json_str)

题目 3:统一 API 响应结构

需求
编写一个辅助类 ApiResponse
包含两个静态方法 success(data)error(code, msg)
返回标准的字典结构:{"code": ..., "msg": ..., "data": ...}

点击查看参考答案
class ApiResponse:
    @staticmethod
    def success(data=None):
        return {
            "code": 200,
            "msg": "Success",
            "data": data
        }

    @staticmethod
    def error(code=400, msg="Error"):
        return {
            "code": code,
            "msg": msg,
            "data": None
        }

print(ApiResponse.success({"user_id": 1}))
print(ApiResponse.error(404, "User not found"))

题目 4:JWT Token 生成与验证

需求
使用 PyJWT 库实现 Token 的生成和验证。
Token 应包含用户 ID 和过期时间。
验证过期 Token 时应返回 None。

点击查看参考答案
import jwt
import time
from datetime import datetime, timedelta, timezone

def create_token(user_id: str, secret: str, expires_seconds: int = 3600):
    """生成 JWT Token"""
    now = datetime.now(timezone.utc)
    payload = {
        "user_id": user_id,
        "exp": now + timedelta(seconds=expires_seconds),
        "iat": now
    }
    return jwt.encode(payload, secret, algorithm="HS256")

def verify_token(token: str, secret: str):
    """验证 JWT Token"""
    try:
        return jwt.decode(token, secret, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        print("Token 已过期")
        return None
    except jwt.InvalidTokenError:
        print("Token 无效")
        return None

# 使用示例
SECRET = "my-secret-key-must-be-at-least-32-bytes-long"

# 生成 Token
token = create_token("user_123", SECRET, expires_seconds=2)
print(f"生成的 Token: {token}")

# 立即验证
payload = verify_token(token, SECRET)
print(f"验证结果: {payload}")

# 等待过期后验证
time.sleep(3)
payload = verify_token(token, SECRET)
print(f"过期后验证: {payload}")

13. 系列索引


写在最后
兄弟们,编程不是一蹴而就的,它是一场长跑。今天你可能还在为配不好环境而苦恼,一年后你可能就能主导一个千万级用户的项目。
保持好奇心,保持空杯心态。
这个系列结束了,但你的全栈之旅才刚刚开始。
如果这个系列对你有帮助,请务必点赞、收藏、关注! 你的支持是我持续产出高质量内容的动力。
咱们江湖再见,代码里见!

更多推荐