当前位置: 首页 > news >正文

从 Apache SeaTunnel 走向 ASF Member:一位开发者的长期主义样本攀

一、中间件是啥?咱用“餐厅”打个比方

想象一下,你的FastAPI应用是个高级餐厅。

?? 顾客(客户端请求)来到门口。

- 迎宾(CORS中间件):先看你是不是从允许的街区(域名)来的,不是就直接劝退(返回CORS错误)。

- 领位员(日志中间件):记下顾客几点来的、几个人。

- 安检(认证中间件):检查你有没有预约码(Token)。

?? 之后,顾客才能见到真正的厨师(你的路径操作函数)点菜吃饭(处理业务逻辑)。

?? 吃完离开时,还得经过传菜员(响应处理中间件),可能给打包盒贴个标签(添加响应头)。

这一系列站在“核心业务”前后的服务人员,就是中间件。它的核心价值在于:全局处理、业务无侵入。

官方文档讲得比较散,咱们今天就把这块硬骨头啃透,直接上代码。

?? 二、核心:怎么用?从最常用的CORS开始

好,咱们先来解决开头的“跨域”问题。这是99%的Web应用都会遇到的。

from fastapi import FastAPI

from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 1. 配置允许的源、方法、请求头

origins = [

"http://localhost:3000", # 你的前端开发地址

"https://your-production-site.com",

]

# 2. 添加中间件

app.add_middleware(

CORSMiddleware,

allow_origins=origins, # 允许的源列表,也可以用 ["*"] 放行所有(不安全!)

allow_credentials=True, # 允许携带Cookie

allow_methods=["*"], # 允许所有方法 (GET, POST, 等)

allow_headers=["*"], # 允许所有请求头

)

@app.get("/")

async def main():

return {"message": "Hello World"}

这里千万别学我当初偷懒,图省事直接上 `allow_origins=["*"]`,这在生产环境是安全大忌,相当于餐厅大门敞开,谁都能进。线上务必明确指定前端域名!

?? 三、动手:写一个自己的中间件

接下来重点来了,自定义中间件。比如,我们要给每个请求记日志,并计算处理耗时。

import time

from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http") # 这是关键装饰器

async def log_request_time(request: Request, call_next):

# 1. 请求进来时

# 这里我们使用 time.perf_counter() 而不是 time.time(),因为它对于这些用例可能更精确

start_time = time.perf_counter()

path = request.url.path

method = request.method

print(f"?? 收到请求: {method} {path}")

# 2. 把请求交给下一个处理环节(可能是其他中间件,或者是最终的路由)

response = await call_next(request)

# 3. 响应返回前

process_time = time.perf_counter() - start_time

response.headers["X-Process-Time"] = str(process_time) # 可以往响应头加东西

print(f"? 请求完成: {method} {path}, 耗时: {process_time:.4f}秒")

return response

@app.get("/test")

async def test():

return {"message": "ok"}

访问 /test,看看控制台,是不是日志和响应头都有了?这就是一个最基础的HTTP中间件。

划重点: 中间件函数接收一个 call_next,它就像接力棒,你必须调用它(await call_next(request)),请求才能继续往后走。你在它前面和后面写的代码,就分别对应了“请求处理”和“响应处理”两个阶段。

?? 四、灵魂拷问:多个中间件,谁先谁后?

你是不是以为加完就完事了?多个中间件的执行顺序是超级易错点!

想象一下,你既加了CORS中间件,又加了上面的日志中间件,还加了一个认证中间件。它们怎么排队?

结论:按照添加的相反顺序执行“请求阶段”,再按照添加的正序执行“响应阶段”。 像洋葱一样,一层层进去,再一层层出来。

app = FastAPI()

# 假设我们按顺序添加三个中间件

app.add_middleware(MiddlewareC) # 第三个添加

app.add_middleware(MiddlewareB) # 第二个添加

app.middleware("http")(middleware_a) # 第一个添加(装饰器写法)

# 实际执行顺序(请求阶段):

# 1. middleware_a 的请求处理代码

# 2. MiddlewareB 的请求处理代码

# 3. MiddlewareC 的请求处理代码

# --- 到达路由函数 ---

# 4. MiddlewareC 的响应处理代码

# 5. MiddlewareB 的响应处理代码

# 6. middleware_a 的响应处理代码

# --- 响应返回给客户端 ---

官方文档虽然说了是“装饰器顺序”,但用 app.add_middleware() 添加时更容易迷糊。记不住就背下这个口诀:“后来居上(请求),原路返回(响应)”。 设计时,要把依赖关系想清楚,比如认证应该放在靠“里”层(后添加),日志可以放在最“外”层(先添加)。

?? 五、进阶:更底层的ASGI中间件

再说个容易翻车的点。上面我们用 @app.middleware("http") 叫HTTP中间件,是FastAPI封装好的。还有一种更底层、更强大的叫ASGI中间件。

它和HTTP中间件啥区别?好比一个是高级餐厅的固定流程(HTTP),另一个是后厨的原子操作(ASGI),能处理WebSocket等更多协议。

怎么用?通常你需要一个第三方库,比如 starlette-context 来在请求中传递全局数据,或者自己封装(FastAPI在fastapi.middleware中提供了几个中间件,仅仅是为了方便开发者,但大多数可用的中间件直接来自Starlette):

from fastapi import FastAPI

from starlette.middleware.base import BaseHTTPMiddleware

class CustomHeaderMiddleware(BaseHTTPMiddleware):

async def dispatch(self, request, call_next):

response = await call_next(request)

response.headers["X-Custom-Header"] = "MyValue"

return response

app = FastAPI()

app.add_middleware(CustomHeaderMiddleware) # 这里添加的就是ASGI中间件

注意: BaseHTTPMiddleware 使用简单,但官方提示可能有轻微性能损耗,因为每个请求都会创建新的类实例。对于超高并发场景,用之前的函数式 @app.middleware("http") 或直接写纯ASGI中间件是更优解。

??匆觅汗笔

http://www.cnnetsun.cn/news/1769147.html

相关文章:

  • 在昇腾Atlas 800I A2上,用vLLM-Ascend 0.9.1-dev部署Qwen2.5-7B的保姆级避坑指南
  • 基于Xinference的向量化模型部署实战:从环境配置到LangChain集成
  • Codex 陷阱:AI 生成代码的安全雷区 —— 路径遍历漏洞深度剖析与防御实战
  • 阿里达摩院:细胞状态硅基模拟+扰动响应分析
  • 改进鲸鱼优化算法(IWOA)的效果与优化空间
  • 从零到一:Vitis AI 开发环境搭建全攻略(VMware + Ubuntu 20.04 + 必备软件)
  • BELTTT:专业太阳能逆变解决方案提供商
  • STM32F103C8T6实战:用AD7606和AD698搞定RVDT角度测量(附完整代码与避坑记录)
  • Agent记忆怎么做?中大团队创新突破
  • 【.NET 9 AI推理性能跃迁指南】:实测提升3.7倍吞吐、降低62%内存占用的7大编译器级优化秘技
  • 算法竞赛选手必看:ICPC香港站H题Mah-jong的三进制状压与双指针解法详解
  • OpenClaw技能组合:Kimi-VL-A3B-Thinking与其他AI模型的管道协作
  • 保姆级避坑指南:在只有一台能上网的服务器上,搞定Proxmox VE 7.0三节点集群和Ceph存储
  • 深入剖析FlashDB TSDB:嵌入式时序数据存储实战指南
  • 1个网关=100+设备兼容:耐达讯自动化CC-Link IE 转 EtherCAT重新定义工业协议转换价值
  • Windows更新修复工具深度技术指南:从问题诊断到系统优化
  • 空间智能底座:破解数字孪生困局,构建可计算物理世界
  • Windows 11终极优化指南:使用Win11Debloat实现系统性能提升的完整教程
  • 什么是MVP? 在项目里如何使用?
  • 实战指南:基于STM32F411CEU6的LED灯控制与按键交互实现
  • Micro-ros实战指南:在STM32平台从零构建自定义消息的ROS2节点
  • claw-code 源码分析:API Client 抽象——多提供商、OAuth、流式响应的统一接口长什么样?
  • 别再写10个函数了!用Arduino数组驱动数码管,代码量减半的秘密
  • 【权威实测|2026.03.15 CPython核心团队签发】:Python原生AOT插件下载失败率骤降92%,但90%开发者仍卡在第2步安装验证
  • 别再只会点鼠标了!用ComfyUI节点搭建你的第一个AI绘画工作流(附避坑清单)
  • KDD 2025前瞻 | 时间序列前沿:从预测、异常检测到测试时适应的核心突破
  • 【高并发DOTS网络同步终极方案】:单服2000实体毫秒级状态同步的确定性帧同步架构,含NetworkStream+JobChunk双缓冲实现
  • 【微软内部泄露文档】:Blazor 2026插件安装失败率高达63.8%?一文破解.NET SDK 9.0.100+环境下的静默崩溃根因
  • 沃思智能路灯改造方案:让城市照明省电50%的科技秘籍
  • 终极模组管理器:XXMI启动器让多游戏模组管理变得简单高效 [特殊字符]