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

catch-all路由

介绍

✅ 什么是 Catch-All 路由?

Catch-All 路由 指的是:一个能匹配“任意路径”的通配型路由。

它一般会使用 路径参数 path 类型,比如:

@app.get("/{full_path:path}")
async def fallback_handler(full_path: str):
    return {"msg": f"You visited: {full_path}"}

这个 / 开头的 /{full_path:path},意思是:
• 匹配任何以 / 开头的请求;
• 把完整的路径作为字符串传入 full_path;
• 哪怕路径是 /foo/bar/hello.jpg,它也能匹配!

所以叫 Catch-All,就像“最后一个网兜”,你没被其他精确路径命中,就会掉进去。

URL 路由匹配机制的一部分,和代码有没有 try-catch 是两码事。

部分含义
/所有路径的开头
{full_path}这是一个路径参数,名字叫 full_path
:path是这个参数的“类型转换器”

🔍 :path 是什么意思?

类型描述
str默认,只匹配不含斜杠 / 的一段
int匹配整数
float匹配浮点数
path✅ 匹配多段路径(包括斜杠 /)

就意味着这个路由会匹配所有请求路径,无论路径有多少层!

也正因如此,它常被叫做 Catch-All(兜底)路由,用于前端 SPA 项目的前端路由支持。

@app.get("/api/user")
def user(): ...

@app.get("/api/task")
def task(): ...

@app.get("/{path:path}")
def fallback(path): ...

访问 /api/user 会进入 user(),访问 /api/task 会进入 task()。

但如果你访问:

• /api/does-not-exist → ❗ 不会 404!

• 会进入 fallback(path),path == “api/does-not-exist”

这就叫 Catch-All。

路由顺序

  1. 它是匹配所有路径的,如果注册早了,就会“截胡”所有后面的路由。

  2. FastAPI 按照注册顺序来判断匹配优先级,谁先注册,谁优先。

  3. 如果 Catch-All 早注册,那就没有“后面”了,你的 /api/v1/** 根本用不上!

🎯 问题核心:setup_admin(app) 是个「兜底路由(catch-all)」

SQLAdmin 或类似的后台管理插件,一般都会注册一个这样的路由:

@app.get("/{full_path:path}")
async def catch_all_route(full_path: str): ...

🚨 所有未被上面 include_router 明确匹配到的路径请求,都会被这个 catch-all 捕获处理。

• 本来这个应该走 user_router 的 CORS 预检流程;

但是如果这个路由在 setup_admin(app) 之后注册了,那么 catch-all 路由先注册,它就优先匹配了!

• 而 catch-all 路由并不会处理跨域(CORS OPTIONS 请求);

• 所以浏览器就报了 CORS 跨域错误 ⚠️

# 1. 注册所有业务接口
app.include_router(api_router1)
app.include_router(api_router2)

# 2. 注册 SQLAdmin(会用 catch-all)
setup_admin(app)

# 3. 注册前端静态资源路由(if any)
app.include_router(web_router.router)

路由找不到报CORS?

FastAPI 的中间件执行顺序 + catch-all 路由的作用范围 + CORS 的工作机制

app.add_middleware(
    CORSMiddleware,  # 跨域处理
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头部
)

✅ 你已经注册了 CORSMiddleware,那为啥还报跨域?

上述代码:

所有经过 FastAPI 路由匹配成功的请求(包括 OPTIONS 预检请求)都会自动添加 Access-Control-Allow-* 相关响应头从而避免跨域错误!

❌ 但为什么“未命中的路由”还会报跨域?

这是核心重点:

🔥CORS 中间件只作用于:能被 FastAPI 接收到的请求

⚠️ 如果这个 Catch-All 路由没有处理 CORS,结果就是:

  1. 浏览器先发出 预检请求 OPTIONS /api/v1/xxx

  2. FastAPI 查找路由匹配不到(因为这个接口没注册或被覆盖);

  3. 匹配到你的 Catch-All;

  4. 但 Catch-All 没有注册 OPTIONS 方法;

  5. FastAPI 返回 405 或 404;

  6. CORSMiddleware 不生效(它只对合法路由生效);

  7. 浏览器就 报跨域错误

这一段已经告诉 FastAPI:我允许跨域请求,包括 OPTIONS 方法。

但!!!问题的关键不是你有没有加 allow_methods=[“*”],而是:

❗ 请求路径 /some/path 根本没注册任何路由!也就没有任何 handler 能接住 OPTIONS 请求!

你要知道:

FastAPI 的 CORS 中间件只会对 存在的路由 生效

❌ 所以:如果你的某个路径根本没被 app.include_router() 注册

比如请求的是 /aichat/pub_agent/expend/dict/,但你没有注册它,那么:

• FastAPI 连 OPTIONS 都不知道该交给谁处理

• 它直接走到了 404 或 405

• 然后 CORS middleware 根本不会处理它

• ✅ 最终结果:浏览器就看到一个没有 CORS headers 的响应,报 CORS error

[请求进来]
     ↓
中间件先处理 (CORSMiddleware 会拦截 OPTIONS 请求)
     ↓
如果请求路径存在 → CORSMiddleware 会自动响应 OPTIONS 并添加 CORS headers ✅
     ↓
如果请求路径不存在 → 中间件不处理,FastAPI 抛出 404

✔ 方法一:确认你的 catch-all 路由支持 OPTIONS 请求

@router.api_route("/{full_path:path}", methods=["GET", "POST", "OPTIONS"])
async def catch_all(full_path: str, request: Request):
    ...

⚠️ 即使你什么都不做,也得让它 return 一个空的响应,这样 CORSMiddleware 就会处理它。

✔ 方法二:手动添加一个兜底的 OPTIONS 响应

from fastapi.responses import Response

@router.options("/{full_path:path}")
async def options_handler(full_path: str):
    return Response()
原因说明
CORS 中间件只对匹配成功的路由生效OPTIONS 预检必须也要命中
Catch-All 如果不支持 OPTIONS,就会报错浏览器就会认为是跨域失败
路由顺序、注册方式影响是否生效后注册的 Catch-All 可能覆盖其他逻辑
http://www.dtcms.com/a/107283.html

相关文章:

  • 数据结构初阶: 顺序表的增删查改
  • 【LeetCode Solutions】LeetCode 126 ~ 130 题解
  • Selenium自动化中的 三大时间等待
  • gcc 链接顺序,静态库循环依赖问题
  • 「青牛科技」GC5849 12V三相无感正弦波电机驱动芯片
  • RISC-V debug专栏2 --- Debug Module(DM)
  • 在将asc文件导入maxent文件时出现for input string:“nan“
  • (kotlin) Android 13 高版本 图片选择、显示与裁剪功能实现
  • Docker容器部署Java项目的自动化脚本(Shell编写)
  • 动态规划练习题①
  • 蓝桥杯 web 灯的颜色变化(Dom操作及样式动态修改、浏览器解析顺序、定时器)
  • 计算机科学基础设施之数学:科研工具、资源与环境详介
  • qt.qpa.xcb: could not connect to display解决方法
  • Keil5烧录后STM32不自动运行?必须复位才能启动的终极解决方案
  • element-plus中,Upload上传组件的使用 + 后端处理
  • DMA在SPI和I2C通信中的应用详解
  • 解锁异步编程新姿势:CompletableFuture 深度探秘
  • java根据集合中对象的属性值大小生成排名
  • [NOIP 1999 提高组] 导弹拦截
  • C++ STL简单的几个容器
  • I²C总线高级特性与故障处理分析
  • 【leetcode100】每日温度
  • OpenCV 从入门到精通(day_04)
  • 面向对象
  • python实现简单fast-cgi服务,对接到nginx
  • 蓝桥云客 刷题统计
  • 持续集成与Jenkins安装使用教程
  • 分布式锁方案-Redisson
  • Linux命令-tar
  • 使用 MapReduce 进行高效数据清洗:从理论到实践