中间件和跨域

中间件是在请求进入路由前、响应返回客户端前执行的一层逻辑。

常见用途:

  • 记录请求日志
  • 统计接口耗时
  • 添加响应头
  • 统一处理跨域
  • 接入链路追踪

一、请求处理流程

客户端请求

中间件:请求进入前

路由函数

中间件:响应返回前

客户端收到响应

二、添加一个耗时响应头

import time

from fastapi import FastAPI, Request

app = FastAPI()


@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start = time.perf_counter()
    response = await call_next(request)
    process_time = time.perf_counter() - start
    response.headers["X-Process-Time"] = f"{process_time:.6f}"
    return response


@app.get("/")
def root():
    return {"message": "Hello FastAPI"}

解释:

代码说明
@app.middleware("http")注册 HTTP 中间件
request当前请求对象
call_next(request)继续执行后面的路由
response.headers[...]给响应添加响应头

打开浏览器开发者工具或用 /docs 调试,可以看到响应头里多了:

X-Process-Time: 0.001234

三、中间件里不要做太重的事

中间件会影响所有请求,所以要保持轻量。

适合做:

  • 记录简单日志
  • 添加请求 ID
  • 统计耗时
  • 统一响应头

不适合做:

  • 大量数据库查询
  • 复杂业务计算
  • 慢速第三方接口调用

复杂业务应该放在路由、service 或后台任务里。

四、什么是跨域 CORS

如果前端页面和后端 API 不在同一个源,就会遇到跨域。

源由三部分组成:

协议 + 域名 + 端口

例如:

地址
http://localhost:5173前端开发服务器
http://127.0.0.1:8000FastAPI 后端

端口不同,所以是不同源。浏览器会限制前端直接调用后端,需要后端允许跨域。

五、配置 CORSMiddleware

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

app = FastAPI()

origins = [
    "http://localhost:5173",
    "http://127.0.0.1:5173",
]

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

参数说明:

参数说明
allow_origins允许哪些前端源访问
allow_credentials是否允许携带 Cookie、认证信息
allow_methods允许哪些 HTTP 方法
allow_headers允许哪些请求头

六、开发环境和生产环境区别

开发环境可以写本地前端地址:

origins = [
    "http://localhost:5173",
    "http://127.0.0.1:5173",
]

生产环境应该写真实域名:

origins = [
    "https://admin.example.com",
    "https://www.example.com",
]

不建议在生产环境里随手写:

allow_origins=["*"]

尤其是接口需要 Cookie 或 Authorization 认证时,应该明确列出允许访问的前端域名。

七、常见跨域问题

现象可能原因
浏览器控制台提示 CORS后端没配置 CORSMiddleware
Postman 能请求,浏览器不能CORS 是浏览器安全策略,Postman 不受限制
带 Token 请求失败allow_headers 没允许相关请求头
带 Cookie 请求失败allow_credentials 或前端请求配置不完整

先记住一点:跨域是浏览器限制,不是 FastAPI 接口本身不能访问。