如何将后端和前端放在一起 - 从 fastapi 后端端点返回react前端

IT技术 reactjs fastapi
2021-05-17 10:25:29

首先,我只想说这是我的第一个 Web 应用程序项目。在过去的几天里,我一直试图找到关于如何从本质上将前端和后端组合在一起的答案。我有很多问题,但我想回答的主要问题是如何从后端端点返回我的前端“最终产品”。

这是我的理解(如果我错了,请纠正我):

  • 前端代码由客户端(浏览器)运行。
  • 当客户端与网页交互时,前端会根据需要向后端调用 API 以检索/修改数据。
  • 后端和前端通常是分开开发的,可以托管在不同的服务器上。
  • 但是,可以(并且可能更简单)将其托管在单个域/服务器上。我希望这样做,以避免 CORS 出现一系列问题。

那么接下来的问题来了:

当我想测试我的前端并查看它的运行情况时,我只需运行npm run start. 然后我转到给定的 url(通常http://localhost:8080/),我可以访问我开发的前端。当我想部署它时,我运行npm run build,它给了我一个dist文件夹(捆绑在一起并缩小)。

如果我想在本地运行和测试我的后端,就像我使用的那样FastAPI,我只需运行uvicorn main:app --reload.

如何将两者结合起来?更具体地说,在我的后端代码中,我如何返回前端工作的产品(即dist文件夹?)。我尝试了以下(简化):

@app.get("/", response_class=HTMLResponse)
def root():
    return open("../frontend/dist/index.html", "r").read()

但是,当然,这只会给我没有 React 组件的静态 html。

我意识到这篇文章可能包含不正确的假设和糟糕的做法(在这种情况下,我很抱歉!我将不胜感激任何更正/建议。)但是,如果可以回答以下问题,我将不胜感激。这些是我的问题,希望能帮助我在我的计算机上本地测试我的整个 Web 应用程序。

  1. 如何为GET域根端点处的请求返回我的前端工作的产品
  2. 如果有一个页面A,页面B和页面下我的web应用程序,每一个URL www.example.com/Awww.example.com/Bwww.example.com/C我有创建三个不同的阵营前端项目?即,相当于拥有三个dist文件夹?处理这种情况的标准方式是什么?
2个回答

运行 Web 应用程序的“传统”方法是拥有一个服务器来为您的 Web 应用程序(即您的 React 应用程序)提供服务。通常您会听说nginx被用作用于现代单页应用程序的 Web 服务器。当你运行时,npm run start你在你的机器上启动一个本地服务器,它使你的应用程序可用http://localhost:8080(端口和主机名当然是可配置的)。

当涉及到你的 API 时,它应该是它自己的服务器在不同的端点/url 上可用,然后你的 Web 应用程序将对那个端点/url 进行 API 调用以获取数据。

您描述事物的方式,听起来您正在尝试使用 FastAPI 来服务器渲染您的 Web 应用程序,但我不确定这有多可行,尤其是考虑到有一个专门用于服务器渲染react应用程序整个框架.

这些都是很好的问题,当然是有可能的。我会告诉你我在做什么,但要注意可能有更好的方法......

我使用的是 Vue 而不是 React,但它的构建过程也会将静态 html、js 和 css 发送到一个dist/目录,因此该过程应该大致相同。

首先,您可以将dist/index.html您提到文件复制到 FastAPItemplates/目录中。您将使用 FastAPI 路由将该文件作为模板提供。

然后将你的 js 和 css 复制到一个static/目录中,并确保 FastAPI 知道静态和模板。

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

app = FastAPI()

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

templates = Jinja2Templates(directory="templates")

@app.get("/")
async def serve_spa(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

您可能需要在 React 中设置一些内容,以便您的构建知道 js 和 css 将位于名为static. 对于 Vue,里面有一个assetsDir选项vue.config.js

对于有关处理不同路径的问题,例如example.com/aexample.com/b,这取决于您希望如何处理这些请求。您是否希望您的单个 React 应用程序处理所有这些路由?

如果是这种情况,您可能还想查看:如何在 FastAPI 中的一个路由上捕获任意路径?

一种选择是复制serve_spa()上述路线和处理您的路线,比如/a/b等等。

或者使用包罗万象的路线:

@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})