查看: 168|回复: 1

FastAPI与Flask后端对接React/Vue全栈集成实践:API设计、CORS与JWT认证

[复制链接]
发表于 4 小时前 | 显示全部楼层 |阅读模式
全栈开发中,Python作为后端语言与前端框架的集成是常见需求。本文结合FastAPI与Flask两种框架,展示如何构建RESTful API并与React、Vue前端进行数据交互,同时解决CORS、JWT认证及部署等关键问题。

一、后端API设计:FastAPI与Flask实现CRUD

1.1 FastAPI版本
FastAPI基于Pydantic模型自动生成文档,适合构建高性能API。以下代码演示了商品的增删改查操作:
  1. from fastapi import FastAPI
  2. from pydantic import BaseModel
  3. from typing import List
  4. app = FastAPI()
  5. class Item(BaseModel):
  6.     id: int
  7.     name: str
  8.     price: float
  9.     is_offer: bool = None
  10. items = []
  11. @app.get("/")
  12. def read_root():
  13.     return {"message": "Hello, World!"}
  14. @app.get("/items/{item_id}")
  15. def read_item(item_id: int):
  16.     for item in items:
  17.         if item.id == item_id:
  18.             return item
  19.     return {"error": "Item not found"}
  20. @app.post("/items/")
  21. def create_item(item: Item):
  22.     items.append(item)
  23.     return item
  24. @app.put("/items/{item_id}")
  25. def update_item(item_id: int, item: Item):
  26.     for i, existing_item in enumerate(items):
  27.         if existing_item.id == item_id:
  28.             items[i] = item
  29.             return item
  30.     return {"error": "Item not found"}
  31. @app.delete("/items/{item_id}")
  32. def delete_item(item_id: int):
  33.     for i, item in enumerate(items):
  34.         if item.id == item_id:
  35.             items.pop(i)
  36.             return {"message": "Item deleted"}
  37.     return {"error": "Item not found"}
复制代码

1.2 Flask版本
Flask轻量灵活,使用request和jsonify处理JSON请求与响应:
  1. from flask import Flask, request, jsonify
  2. app = Flask(__name__)
  3. items = []
  4. @app.route('/', methods=['GET'])
  5. def read_root():
  6.     return jsonify({"message": "Hello, World!"})
  7. @app.route('/items/<int:item_id>', methods=['GET'])
  8. def read_item(item_id):
  9.     for item in items:
  10.         if item['id'] == item_id:
  11.             return jsonify(item)
  12.     return jsonify({"error": "Item not found"})
  13. @app.route('/items/', methods=['POST'])
  14. def create_item():
  15.     item = request.get_json()
  16.     items.append(item)
  17.     return jsonify(item)
  18. @app.route('/items/<int:item_id>', methods=['PUT'])
  19. def update_item(item_id):
  20.     item = request.get_json()
  21.     for i, existing_item in enumerate(items):
  22.         if existing_item['id'] == item_id:
  23.             items[i] = item
  24.             return jsonify(item)
  25.     return jsonify({"error": "Item not found"})
  26. @app.route('/items/<int:item_id>', methods=['DELETE'])
  27. def delete_item(item_id):
  28.     for i, item in enumerate(items):
  29.         if item['id'] == item_id:
  30.             items.pop(i)
  31.             return jsonify({"message": "Item deleted"})
  32.     return jsonify({"error": "Item not found"})
  33. if __name__ == '__main__':
  34.     app.run(debug=True)
复制代码

二、前端集成:React与Vue调用API

2.1 React集成
使用useState和useEffect实现数据获取与提交:
  1. import React, { useState, useEffect } from 'react';
  2. function App() {
  3.   const [items, setItems] = useState([]);
  4.   const [newItem, setNewItem] = useState({ id: '', name: '', price: '', is_offer: false });
  5.   useEffect(() => {
  6.     fetch('http://localhost:8000/items/')
  7.       .then(response => response.json())
  8.       .then(data => setItems(data));
  9.   }, []);
  10.   const handleSubmit = (e) => {
  11.     e.preventDefault();
  12.     fetch('http://localhost:8000/items/', {
  13.       method: 'POST',
  14.       headers: { 'Content-Type': 'application/json' },
  15.       body: JSON.stringify(newItem),
  16.     })
  17.       .then(response => response.json())
  18.       .then(data => {
  19.         setItems([...items, data]);
  20.         setNewItem({ id: '', name: '', price: '', is_offer: false });
  21.       });
  22.   };
  23.   return (
  24.     <div>
  25.       <h1>Items</h1>
  26.       <ul>
  27.         {items.map(item => (
  28.           <li key={item.id}>{item.name} - ${item.price}</li>
  29.         ))}
  30.       </ul>
  31.       <form onSubmit={handleSubmit}>
  32.         <input type="text" placeholder="ID" value={newItem.id} onChange={(e) => setNewItem({...newItem, id: parseInt(e.target.value)})} />
  33.         <input type="text" placeholder="Name" value={newItem.name} onChange={(e) => setNewItem({...newItem, name: e.target.value})} />
  34.         <input type="number" placeholder="Price" value={newItem.price} onChange={(e) => setNewItem({...newItem, price: parseFloat(e.target.value)})} />
  35.         <button type="submit">Add Item</button>
  36.       </form>
  37.     </div>
  38.   );
  39. }
  40. export default App;
复制代码

2.2 Vue集成
使用Vue的data、mounted和methods实现同样功能:
  1. <template>
  2.   <div>
  3.     <h1>Items</h1>
  4.     <ul>
  5.       <li v-for="item in items" :key="item.id">{{ item.name }} - ${{ item.price }}</li>
  6.     </ul>
  7.     <form @submit.prevent="handleSubmit">
  8.       <input type="text" placeholder="ID" v-model.number="newItem.id" />
  9.       <input type="text" placeholder="Name" v-model="newItem.name" />
  10.       <input type="number" placeholder="Price" v-model.number="newItem.price" />
  11.       <button type="submit">Add Item</button>
  12.     </form>
  13.   </div>
  14. </template>
  15. <script>
  16. export default {
  17.   data() {
  18.     return {
  19.       items: [],
  20.       newItem: { id: '', name: '', price: '', is_offer: false }
  21.     };
  22.   },
  23.   mounted() {
  24.     this.fetchItems();
  25.   },
  26.   methods: {
  27.     fetchItems() {
  28.       fetch('http://localhost:8000/items/')
  29.         .then(response => response.json())
  30.         .then(data => { this.items = data; });
  31.     },
  32.     handleSubmit() {
  33.       fetch('http://localhost:8000/items/', {
  34.         method: 'POST',
  35.         headers: { 'Content-Type': 'application/json' },
  36.         body: JSON.stringify(this.newItem),
  37.       })
  38.         .then(response => response.json())
  39.         .then(data => {
  40.           this.items.push(data);
  41.           this.newItem = { id: '', name: '', price: '', is_offer: false };
  42.         });
  43.     }
  44.   }
  45. };
复制代码

三、数据传输与CORS处理

默认JSON格式传输,但前后端域名不同时会触发跨域错误。FastAPI和Flask均需显式配置CORS。

FastAPI中通过CORSMiddleware允许所有来源(生产环境应限定域名):
  1. from fastapi.middleware.cors import CORSMiddleware
  2. app.add_middleware(
  3.     CORSMiddleware,
  4.     allow_origins=["*"],
  5.     allow_credentials=True,
  6.     allow_methods=["*"],
  7.     allow_headers=["*"]
  8. )
复制代码

Flask中安装flask-cors后直接初始化:
  1. from flask_cors import CORS
  2. app = Flask(__name__)
  3. CORS(app)
复制代码

四、JWT认证实现

FastAPI结合python-jose库实现JWT生成与验证。以下模拟用户数据库进行登录与保护路由:
  1. from fastapi import FastAPI, Depends, HTTPException, status
  2. from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
  3. from jose import JWTError, jwt
  4. from datetime import datetime, timedelta
  5. SECRET_KEY = "your-secret-key"
  6. ALGORITHM = "HS256"
  7. ACCESS_TOKEN_EXPIRE_MINUTES = 30
  8. fake_users_db = {
  9.     "alice": {
  10.         "username": "alice",
  11.         "full_name": "Alice Smith",
  12.         "email": "alice@example.com",
  13.         "hashed_password": "fakehashedsecret",
  14.         "disabled": False
  15.     }
  16. }
  17. def fake_hash_password(password: str):
  18.     return "fakehashed" + password
  19. def verify_password(plain_password, hashed_password):
  20.     return hashed_password == fake_hash_password(plain_password)
  21. def get_user(db, username: str):
  22.     return db.get(username)
  23. def create_access_token(data: dict, expires_delta: timedelta = None):
  24.     to_encode = data.copy()
  25.     expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
  26.     to_encode.update({"exp": expire})
  27.     return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
  28. oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
  29. async def get_current_user(token: str = Depends(oauth2_scheme)):
  30.     credentials_exception = HTTPException(
  31.         status_code=status.HTTP_401_UNAUTHORIZED,
  32.         detail="Could not validate credentials",
  33.         headers={"WWW-Authenticate": "Bearer"}
  34.     )
  35.     try:
  36.         payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
  37.         username: str = payload.get("sub")
  38.         if username is None:
  39.             raise credentials_exception
  40.     except JWTError:
  41.         raise credentials_exception
  42.     user = get_user(fake_users_db, username=username)
  43.     if user is None:
  44.         raise credentials_exception
  45.     return user
  46. @app.post("/token")
  47. async def login(form_data: OAuth2PasswordRequestForm = Depends()):
  48.     user = get_user(fake_users_db, form_data.username)
  49.     if not user or not verify_password(form_data.password, user["hashed_password"]):
  50.         raise HTTPException(status_code=400, detail="Incorrect username or password")
  51.     access_token = create_access_token(
  52.         data={"sub": user["username"]},
  53.         expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
  54.     )
  55.     return {"access_token": access_token, "token_type": "bearer"}
  56. @app.get("/users/me")
  57. async def read_users_me(current_user: dict = Depends(get_current_user)):
  58.     return current_user
复制代码

五、部署方案

后端使用Docker容器化部署,Dockerfile示例如下:
  1. FROM python:3.9-slim
  2. WORKDIR /app
  3. COPY requirements.txt .
  4. RUN pip install --no-cache-dir -r requirements.txt
  5. COPY . .
  6. EXPOSE 8000
  7. CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
复制代码

前端可部署至Vercel(适合React/Next.js)、Netlify(Vue/React)或GitHub Pages。若需前后端联调,使用Docker Compose编排:
  1. version: '3'
  2. services:
  3.   backend:
  4.     build: ./backend
  5.     ports:
  6.       - "8000:8000"
  7.   frontend:
  8.     build: ./frontend
  9.     ports:
  10.       - "3000:3000"
  11.     depends_on:
  12.       - backend
复制代码

六、常见问题与解决方案

跨域问题通过CORS中间件解决;认证问题使用JWT标准流程;部署时利用Docker保持环境一致性。性能优化方面建议接口加入缓存层(如Redis),并合理设计数据库查询。

总结:Python(FastAPI/Flask)与前端(React/Vue)的组合能够高效构建全栈应用。掌握API设计、CORS配置、JWT认证和容器化部署是打通前后端的关键步骤。实践时可从简单的CRUD项目入手,逐步集成认证与部署,通过项目驱动巩固知识。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: FastAPI与Flask后端对接React/Vue全栈集成实践:API设计、CORS与JWT认证

感谢分享这么详细的实践内容!FastAPI 和 Flask 的 CRUD 代码对比很清晰,对刚接触前后端集成的开发者来说非常友好。特别是同时展示了两种框架的处理方式,能帮助大家根据项目需求灵活选择。期待后续能补充 CORS 配置和 JWT 认证的具体实现,这部分在实际全栈项目中往往是绕不开的坑,如果能结合 React/Vue 的拦截器或 axios 的配置讲解,会让整套方案更完整。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-20 14:02 , Processed in 0.033130 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部