在FastAPI中挂载Flask应用后访问/api路由出现404错误如何解决?
问题原因
当你将Flask应用挂载到FastAPI的根路径"/"时,Starlette(FastAPI的底层框架)会将所有以"/"开头的请求(也就是所有请求)优先转发给Flask应用处理。这导致FastAPI定义的/api路由永远不会被触发——因为请求先被Flask接收,而Flask没有对应的/api路由,所以返回404错误。
解决方法
你需要调整挂载策略,让FastAPI先处理自身的路由,再将特定路径(比如根路径"/")转发给Flask应用。以下是两种可行方案:
方案一:挂载Flask到子路径并代理根请求
将Flask挂载到一个非根的子路径,然后通过FastAPI的根路由将请求代理到Flask应用:
from fastapi import FastAPI, Request from fastapi.middleware.wsgi import WSGIMiddleware from fastapi.responses import Response from flask import Flask fastapi = FastAPI() app = Flask(__name__) # 将Flask挂载到子路径(比如"/flask_internal") fastapi.mount("/flask_internal", WSGIMiddleware(app=app)) # FastAPI根路由代理到Flask的根路径 @fastapi.get("/") async def forward_to_flask_root(request: Request): # 修改请求路径指向挂载的Flask子路径 scope = request.scope.copy() scope["path"] = "/flask_internal/" + scope["path"].lstrip("/") # 调用Flask的WSGI应用处理请求 response = await app.wsgi_app(scope, request.receive) return Response( content=response.body, status_code=response.status, headers=dict(response.headers) ) # FastAPI的/api路由 @fastapi.get("/api") def test(): return {"hello": "world"} # Flask的根路由(保留一个装饰器即可) @app.route('/') def index(): return "Hello world"
方案二:使用中间件仅处理根路径
如果只需要Flask处理根路径"/",其他路径都由FastAPI处理,可以使用自定义中间件:
from fastapi import FastAPI, Request from fastapi.responses import Response from flask import Flask from starlette.middleware.base import BaseHTTPMiddleware fastapi = FastAPI() app = Flask(__name__) # Flask的根路由 @app.route('/') def index(): return "Hello world" # FastAPI的/api路由 @fastapi.get("/api") def test(): return {"hello": "world"} # 自定义中间件:仅将根路径请求转发给Flask class FlaskRootMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): if request.url.path == "/": # 转发请求给Flask response = await app.wsgi_app(request.scope, request.receive) return Response( content=response.body, status_code=response.status, headers=dict(response.headers) ) # 其他路径由FastAPI处理 return await call_next(request) # 给FastAPI添加中间件 fastapi.add_middleware(FlaskRootMiddleware)
额外优化
你的Flask路由代码中@app.get("/")和@app.route('/')是重复的,@app.route('/')默认已经处理GET请求,保留其中一个即可。
内容的提问来源于stack exchange,提问作者Pourya Mohamadi
相关产品推荐
相关产品推荐

