Python 中间件是连接应用程序不同组件、处理请求与响应的关键机制,在 Web 开发、网络爬虫等领域广泛应用。其核心作用是提供一种非侵入式的方式来扩展和增强应用功能,例如处理认证、日志记录、错误处理、数据压缩和跨域请求等 [ref_1]。下面将根据不同框架和应用场景,详细介绍常用的中间件。
### 一、Web 框架中的中间件
在 Web 开发中,中间件在请求到达视图函数之前和响应返回给客户端之后执行逻辑。
#### 1. FastAPI 中间件
FastAPI 基于 Starlette,支持标准的 ASGI 中间件。其使用方式灵活,既可以通过装饰器直接定义,也可以通过继承 `BaseHTTPMiddleware` 类来创建。
* **基础用法**:使用 `@app.middleware("http")` 装饰器定义一个中间件函数,用于计算请求处理时间 [ref_1]。
```python
import time
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request) # 调用下一个中间件或路由处理函数 [ref_1]
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
```
* **类继承方式(推荐用于复杂逻辑)**:创建一个继承自 `BaseHTTPMiddleware` 的类,在 `dispatch` 方法中实现逻辑,这更利于模块化管理 [ref_1]。
```python
import time
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
class UseTimeMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next) -> Response:
start_time = time.time()
result = await call_next(request)
process_time = time.time() - start_time
result.headers["X-Process-Time"] = str(process_time)
return result
```
然后使用 `app.add_middleware(UseTimeMiddleware)` 进行注册 [ref_1]。
* **常用内置中间件**:
* **`CORSMiddleware`**:处理跨域资源共享(CORS),是构建前后端分离应用的必备组件 [ref_1]。
```python
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许的来源列表
allow_credentials=True,
allow_methods=["*"], # 允许的 HTTP 方法
allow_headers=["*"], # 允许的 HTTP 头
)
```
* **`GZipMiddleware`**:对响应内容进行 Gzip 压缩,减少网络传输数据量,提升性能 [ref_1]。
```python
from fastapi.middleware.gzip import GZipMiddleware
app.add_middleware(GZipMiddleware, minimum_size=500)
```
* **执行顺序**:FastAPI 中间件的注册顺序与执行顺序**相反**,即后注册的中间件先执行(类似栈结构)。可以通过在注册函数中反转列表来调整,使其符合“先注册先执行”的直觉 [ref_1]。
#### 2. Django 中间件
Django 的中间件是一个轻量级、底层的“插件”系统,用于全局改变 Django 的输入或输出。
* **常用内置中间件**:
| 中间件类 | 主要功能 |
| :--- | :--- |
| `django.middleware.security.SecurityMiddleware` | 提供多种安全增强功能,如设置安全相关的 HTTP 头。 |
| `django.middleware.common.CommonMiddleware` | 处理 URL 规范化、禁止用户代理访问等通用任务。 |
| `django.middleware.csrf.CsrfViewMiddleware` | 添加 CSRF(跨站请求伪造)保护。 |
| `django.middleware.clickjacking.XFrameOptionsMiddleware` | 通过设置 `X-Frame-Options` 头来防止点击劫持。 |
| `django.contrib.sessions.middleware.SessionMiddleware` | 启用会话(session)支持。 |
| `django.contrib.auth.middleware.AuthenticationMiddleware` | 将用户与请求关联。 |
| `django.middleware.locale.LocaleMiddleware` | 基于请求数据进行语言偏好设置。 |
* **自定义中间件**:一个 Django 中间件是一个包含特定方法(如 `__init__`, `__call__`, `process_request`, `process_response` 等)的类。需要在 `settings.py` 的 `MIDDLEWARE` 列表中进行配置。
#### 3. Flask 中间件
Flask 本身不直接提供与 Django 或 FastAPI 类似的内置中间件系统,但其基于 WSGI,可以使用符合 WSGI 规范的中间件。更常见的模式是使用**装饰器**或**钩子函数(如 `@app.before_request`, `@app.after_request`)** 来实现类似中间件的功能。
* **使用钩子函数**:
```python
from flask import Flask, g, request
import time
app = Flask(__name__)
@app.before_request
def before_request():
g.start_time = time.time() # 将开始时间存入全局对象 g
@app.after_request
def after_request(response):
process_time = time.time() - g.start_time
response.headers['X-Process-Time'] = str(process_time)
return response
```
* **使用 WSGI 中间件**:可以包装 Flask 应用对象。
```python
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
```
### 二、爬虫框架中的中间件
在 Scrapy 框架中,中间件是扩展其功能的核心机制,主要分为**下载器中间件(Downloader Middleware)** 和 **爬虫中间件(Spider Middleware)** [ref_2][ref_3][ref_4][ref_5][ref_6]。
| 中间件类型 | 作用对象 | 主要功能与场景 |
| :--- | :--- | :--- |
| **下载器中间件** | 引擎与下载器之间 | 处理发往下载器的请求(`process_request`)和从下载器返回的响应(`process_response`)或异常(`process_exception`)。常用于设置代理、更换 User-Agent、处理 Cookies、重试失败请求等 [ref_3][ref_4][ref_6]。 |
| **爬虫中间件** | 引擎与爬虫之间 | 处理从引擎发送给爬虫的响应(`process_spider_input`)和从爬虫返回的结果或请求(`process_spider_output`、`process_start_requests`)以及爬虫异常(`process_spider_exception`)。常用于初步过滤响应、修改爬虫的初始请求等 [ref_3][ref_4]。 |
* **自定义下载器中间件示例(随机 User-Agent)**:
```python
import random
from scrapy import signals
class RandomUserAgentMiddleware:
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...',
# ... 更多 User-Agent
]
def process_request(self, request, spider):
request.headers['User-Agent'] = random.choice(self.user_agents) # 为请求随机设置 User-Agent [ref_6]
return None # 返回 None 表示继续处理该请求
```
需要在 `settings.py` 中启用并设置优先级:
```python
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.RandomUserAgentMiddleware': 543, # 数字代表优先级,越小越先执行
}
```
### 三、消息队列与任务队列中的中间件
在分布式系统中,中间件也指代如 RabbitMQ、Redis、Kafka 等消息代理或任务队列。虽然它们不是代码层面的“函数”或“类”,但作为系统架构中的核心组件,承担着解耦、缓冲、异步通信等中间件角色。例如,Celery 任务队列使用 Redis 或 RabbitMQ 作为中间件来传递任务消息。
### 四、自定义中间件的通用设计模式
无论何种框架,一个健壮的中间件通常遵循以下模式:
1. **初始化**:接收应用实例或配置。
2. **请求预处理**:在请求被核心业务逻辑处理前执行(如身份验证、日志记录、数据注入)。
3. **调用链传递**:调用 `call_next`(FastAPI/ASGI)或返回 `None`(Scrapy)将请求/控制权传递给下一个处理单元。
4. **响应后处理**:在得到响应后执行(如添加头部信息、格式化数据、错误处理)。
5. **异常处理**:捕获并处理流程中可能出现的异常。
例如,一个用于 JWT(JSON Web Token)认证的 FastAPI 中间件可以这样实现 [ref_1]:
```python
import jwt
from fastapi import Request, HTTPException, status
from starlette.middleware.base import BaseHTTPMiddleware
class JWTMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
token = request.headers.get("Authorization")
if not token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="未提供凭证")
try:
# 验证并解码 JWT token [ref_1]
payload = jwt.decode(token.split(" ")[1], "your-secret-key", algorithms=["HS256"])
request.state.user = payload # 将用户信息存入请求状态
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="凭证已过期")
except jwt.InvalidTokenError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="无效凭证")
response = await call_next(request)
return response
```
总之,Python 中的中间件是构建可扩展、可维护应用的重要工具。在 Web 开发中,它用于处理 HTTP 生命周期的横切关注点;在爬虫中,它用于精细控制请求与响应的流程。选择合适的中间件并理解其执行顺序,对于构建高效的 Python 应用至关重要。