FastAPI POST数据传递与页面跳转指南

作者:技术拾光

时间:2026-05-25

浏览:496

在FastAPI等现代Web框架中,处理用户表单提交并跳转至结果页面,是一个常见但易出错的需求。许多开发者会遇到这样的困惑:为何在GET路由中直接调用处理POST数据的异步函数,会引发AttributeError: 'Body' object has no attribute 'casefold'这

文章目录

在FastAPI等现代Web框架中,处理用户表单提交并跳转至结果页面,是一个常见但易出错的需求。许多开发者会遇到这样的困惑:为何在GET路由中直接调用处理POST数据的异步函数,会引发AttributeError: 'Body' object has no attribute 'casefold'这类错误?

FastAPI POST数据传递与页面跳转指南

问题的根源在于对HTTP协议与FastAPI请求生命周期的理解。@app.post与@app.get是两个独立的处理单元。POST请求负责接收、校验和处理请求体(Body)数据,而GET请求通常用于获取资源或渲染页面,其本身不包含请求体。若在GET路由中调用一个期望prompt = Body()参数的函数,FastAPI无法提供请求体,传入参数将变为None或无效对象,后续调用.casefold()方法时便会出错。

正确的解决思路在于职责分离:

  • POST接口专注于接收数据、执行业务逻辑并返回结果。
  • 前端在获取结果后,负责数据的传递与页面跳转。
  • GET页面仅负责展示已准备好的数据。

推荐方案:使用 sessionStorage 暂存与前端跳转

在多种跨请求数据传递方案中,sessionStorage因其轻量、安全且生命周期与浏览器标签页绑定的特性,成为解决此类问题的首选。它无需服务端维护状态,完美契合“提交-跳转-展示”的单次交互场景。

1. 前端逻辑改造:从提交到跳转

首先,需阻止表单或链接的默认跳转行为,改用JavaScript控制流程。



  

核心JavaScript代码如下:

const el = document.getElementById('btn');
el.addEventListener('click', async function () {
  const promptValue = document.getElementById("prompt").value.trim();
  if (!promptValue) return;

  try {
    // 1. 向POST接口发送搜索请求
    const response = await fetch("/get_books", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ prompt: promptValue }) // 键名需与后端参数定义匹配
    });
    if (!response.ok) throw new Error(`HTTP ${response.status}`);

    const bookList = await response.json();

    // 2.  关键步骤:将结果存入sessionStorage
    sessionStorage.setItem('searchResult', JSON.stringify(bookList));
    sessionStorage.setItem('searchPrompt', promptValue);

    // 3.  执行页面跳转(URL不携带参数)
    window.location.href = '/books';
  } catch (err) {
    console.error("搜索失败:", err);
    // 可在此添加用户友好的错误提示
  }
});

2. 优化后端FastAPI接口

后端的POST接口需明确声明参数,并专注于业务处理。

from fastapi import APIRouter, Body, Request
from fastapi.responses import HTMLResponse

@app.post('/get_books')
async def get_books(prompt: str = Body(..., embed=True)): #  明确prompt为必需字符串参数
    print(f"Received prompt: '{prompt}'")
    book_list = []
    for book in BOOKS:
        title = book.get('title', '').casefold()
        author = book.get('author', '').casefold()
        category = book.get('category', '').casefold()
        if prompt.casefold() in (title, author, category):
            book_list.append(book)
    return book_list #  FastAPI会自动将列表序列化为JSON响应

注意:Body(..., embed=True)表示期望接收如{"prompt": "关键词"}的JSON对象。若前端发送的键名不同,例如{info: "xxx"},则后端参数应调整为info: str = Body(..., alias="info")。

3. 更新GET路由:渲染页面而非处理数据

sessionStorage是浏览器端概念,服务端无法直接访问。因此,/books的GET路由任务变得纯粹:返回一个空的HTML模板,由前端自行填充数据。

@app.get('/books', response_class=HTMLResponse)
async def books(request: Request):
    #  重要:此处不再调用get_books()函数!
    return templates.TemplateResponse("books.html", {"request": request})

数据渲染工作移交至books.html模板的初始化脚本:


实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章