如何在 FastAPI 中的一条路径上捕获任意路径?

新手上路,请多包涵

我通过安装从 FastAPI 服务 React 应用程序

app.mount("/static", StaticFiles(directory="static"), name="static")

@app.route('/session')
async def renderReactApp(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

通过这个 React 应用程序得到服务并且 React 路由在客户端也可以正常工作但是一旦客户端重新加载到未在服务器上定义但在 React 应用程序中使用的路由 FastAPI 返回 not found 解决这个问题我做了一些事情如下。

  • @app.route('/network')
  • @app.route('/gat')
  • @app.route('/session')

 async def renderReactApp(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

但这对我来说似乎很奇怪和错误,因为我需要在后端和前端添加每条路线。

我确定在 FastAPI 中必须有类似 Flask @flask_app.add_url_rule('/<path:path>', 'index', index) 的东西,它将为所有任意路径提供服务

原文由 Suhas More 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 899
2 个回答

由于 FastAPI 基于 Starlette,您可以在路由参数中使用他们所谓的“转换器”,使用类型 path 在这种情况下,它“返回路径的其余部分,包括任何额外的 / 字符。”

请参阅 https://www.starlette.io/routing/#path-parameters 以供参考。

如果您的 React(或 Vue 或…)应用程序正在使用基本路径,您可以执行类似的操作,它将 /my-app/ 之后的任何内容分配给 rest_of_path 变量:

 @app.get("/my-app/{rest_of_path:path}")
async def serve_my_app(request: Request, rest_of_path: str):
    print("rest_of_path: "+rest_of_path)
    return templates.TemplateResponse("index.html", {"request": request})

如果您没有使用像 /my-app/ 这样的唯一基本路径(这似乎是您的用例),您仍然可以使用包罗万象的路线来完成此操作,该路线应该遵循任何其他路线,这样它就不会’ 覆盖它们:

 @app.route("/{full_path:path}")
async def catch_all(request: Request, full_path: str):
    print("full_path: "+full_path)
    return templates.TemplateResponse("index.html", {"request": request})

(事实上 ,你会想要使用这个包罗万象的方式来捕捉请求之间的区别 /my-app//my-app

原文由 csum 发布,翻译遵循 CC BY-SA 4.0 许可协议

react-router

我做了一个非常简单的功能,它完全兼容 react-routercreate-react-app 应用程序(大多数用例)

功能

from pathlib import Path
from typing import Union

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

def serve_react_app(app: FastAPI, build_dir: Union[Path, str]) -> FastAPI:
    """Serves a React application in the root directory `/`

    Args:
        app: FastAPI application instance
        build_dir: React build directory (generated by `yarn build` or
            `npm run build`)

    Returns:
        FastAPI: instance with the react application added
    """
    if isinstance(build_dir, str):
        build_dir = Path(build_dir)

    app.mount(
        "/static/",
        StaticFiles(directory=build_dir / "static"),
        name="React App static files",
    )
    templates = Jinja2Templates(directory=build_dir.as_posix())

    @app.get("/{full_path:path}")
    async def serve_react_app(request: Request, full_path: str):
        """Serve the react app
        `full_path` variable is necessary to serve each possible endpoint with
        `index.html` file in order to be compatible with `react-router-dom
        """
        return templates.TemplateResponse("index.html", {"request": request})

    return app

用法

import uvicorn
from fastapi import FastAPI

app = FastAPI()

path_to_react_app_build_dir = "./frontend/build"
app = serve_react_app(app, path_to_react_app_build_dir)

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8001)

原文由 Angel 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题