FastAPI中如何通过RedirectResponse从POST跳转至GET路由并传参
FastAPI中RedirectResponse传递数据的问题
我在FastAPI里想通过RedirectResponse从app.post()向app.get()传递数据,现有代码如下:
GET接口代码
@app.get('/', response_class=HTMLResponse, name='homepage') async def get_main_data(request: Request, msg: Optional[str] = None, result: Optional[str] = None): if msg: response = templates.TemplateResponse('home.html', {'request': request, 'msg': msg}) elif result: response = templates.TemplateResponse('home.html', {'request': request, 'result': result}) else: response = templates.TemplateResponse('home.html', {'request': request}) return response
POST接口代码
@app.post('/', response_model=FormData, name='homepage_post') async def post_main_data(request: Request, file: FormData = Depends(FormData.as_form)): if condition: # 业务逻辑处理 return RedirectResponse(request.url_for('homepage', **{'result': str(trans)}), status_code=status.HTTP_302_FOUND) return RedirectResponse(request.url_for('homepage', **{'msg': str(err)}), status_code=status.HTTP_302_FOUND)
运行时遇到错误:
starlette.routing.NoMatchFound: No route exists for name "homepage" and params "result".
之后尝试手动拼接URL的方式可以正常工作,但参数会暴露在URL中:
return RedirectResponse(app.url_path_for(name='homepage') + '?result=' + str(trans), status_code=status.HTTP_303_SEE_OTHER)
现在需要解决两个问题:
- 如何通过
RedirectResponse和url_for()向app.get()传递result或msg参数? - 有没有办法隐藏URL中的数据(无论作为路径参数还是查询参数)?该如何实现?
问题解答
1. 用url_for()传递查询参数的正确方式
你遇到的NoMatchFound错误是因为url_for()默认会把传入的参数当作路径参数匹配路由规则,但你的homepage路由里的msg和result是查询参数(不是路径占位符)。以下是两种正确实现方式:
方法一:使用include_query_params
通过URL对象的include_query_params方法显式添加查询参数:
from starlette.datastructures import URL # 在POST接口中修改返回逻辑 return RedirectResponse( URL(request.url_for('homepage')).include_query_params(result=str(trans)), status_code=status.HTTP_303_SEE_OTHER )
方法二:直接传入参数(自动识别查询参数)
FastAPI/Starlette支持直接传入非路径参数,会自动转为查询参数,只要路由函数参数未在路径中定义即可:
return RedirectResponse( request.url_for('homepage', result=str(trans)), status_code=status.HTTP_303_SEE_OTHER )
如果之前报错,可能是版本兼容性问题,确保使用FastAPI 0.95+版本即可正常工作。
2. 隐藏URL中的数据
HTTP重定向机制(3xx状态码)本质是引导浏览器跳转新URL,常规方式下数据必然会暴露在URL中。要隐藏数据,推荐以下两种方案:
方案一:使用Session会话存储数据
利用服务器端Session存储数据,重定向后从Session中读取,完全隐藏参数:
步骤1:配置Session中间件
from starlette.middleware.sessions import SessionMiddleware app = FastAPI() # secret_key需替换为随机安全字符串 app.add_middleware(SessionMiddleware, secret_key="your-secure-random-key")
步骤2:POST接口存入Session
@app.post('/', name='homepage_post') async def post_main_data(request: Request, file: FormData = Depends(FormData.as_form)): if condition: request.session['result'] = str(trans) else: request.session['msg'] = str(err) return RedirectResponse(request.url_for('homepage'), status_code=status.HTTP_303_SEE_OTHER)
步骤3:GET接口读取并清理Session
@app.get('/', response_class=HTMLResponse, name='homepage') async def get_main_data(request: Request): msg = request.session.pop('msg', None) result = request.session.pop('result', None) context = {'request': request} if msg: context['msg'] = msg elif result: context['result'] = result return templates.TemplateResponse('home.html', context)
使用pop取出数据后会从Session中删除,避免刷新页面重复显示内容。
方案二:自动提交隐藏表单(不推荐)
返回一个自动提交的HTML表单,将数据放在隐藏字段中,引导浏览器发起POST请求:
@app.post('/', name='homepage_post') async def post_main_data(request: Request, file: FormData = Depends(FormData.as_form)): if condition: return HTMLResponse(f""" <form id="autoSubmitForm" method="POST" action="{request.url_for('hidden_data_handler')}"> <input type="hidden" name="result" value="{str(trans)}"> </form> <script>document.getElementById('autoSubmitForm').submit();</script> """) # 错误处理逻辑类似
新增处理隐藏数据的接口:
@app.post('/hidden-data', response_class=HTMLResponse) async def hidden_data_handler(request: Request, result: Optional[str] = Form(None), msg: Optional[str] = Form(None)): context = {'request': request} if msg: context['msg'] = msg elif result: context['result'] = result return templates.TemplateResponse('home.html', context)
该方式虽能隐藏URL参数,但不符合标准PRG模式,用户体验较差,仅作为备选方案。
内容的提问来源于stack exchange,提问作者Pritam Sinha
相关产品推荐
相关产品推荐

