提问人:Aniket Tiratkar 提问时间:3/14/2023 最后编辑:Brian Tompsett - 汤莱恩Aniket Tiratkar 更新时间:11/19/2023 访问量:2296
如何在 FastAPI 中将请求重新路由到不同的 URL/端点?
How to re-route requests to a different URL/endpoint in FastAPI?
问:
我正在尝试在我的 FastAPI 应用程序中编写一个中间件,以便来自与特定格式匹配的端点的请求将被重新路由到不同的 URL,但我无法找到一种方法来做到这一点,因为是只读的。request.url
我也在寻找一种在重新路由之前更新请求标头的方法。
这些事情在 FastAPI 中是否可能?
重定向是迄今为止我能做的最好的:
from fastapi import Request
from fastapi.responses import RedirectResponse
@app.middleware("http")
async def redirect_middleware(request: Request, call_next):
if matches_certain_format(request.url.path):
new_url = create_target_url(request.url.path)
return RedirectResponse(url=new_url)
答:
0赞
SyntaxNavigator
3/14/2023
#1
是的,FastAPI 应用程序允许 URL 重写。但是,正如您提到的,request.url 是不可变的,因此您无法更新它。
相反,您可以创建一个新的 URL 对象,并使用更新的 URL 和标头将其传递给请求对象。下面是一个同时执行 URL 重写和标头修改的中间件示例:
from fastapi import Request
from fastapi.responses import RedirectResponse
@app.middleware("http")
async def redirect_middleware(request: Request, call_next):
if matches_certain_format(request.url.path):
new_url = create_target_url(request.url.path)
headers = request.headers.copy()
headers['new-header'] = 'new-value'
new_request = Request(request.scope, request.receive, request.app, request.method, URL(new_url), headers=headers)
return await call_next(new_request)
else:
response = await call_next(request)
return response
评论
1赞
Aniket Tiratkar
3/14/2023
这是行不通的。首先,会失败,因为标头没有方法。假设我们在这里使用,那么它将失败,因为它是只读的。谢谢你的回答。request.headers.copy()
copy
copy.copy
headers['new-header'] = 'new-value'
0赞
cactus
11/23/2023
我实际上尝试了这种方法,只修改 URL 而不是标头,以创建new_request并得到: TypeError: __init__() 得到了一个意外的关键字参数“headers”。但是标头还包含“host”标头,我猜也需要将其修改为新 URL......而且确实没有 copy() 方法
3赞
Chris
3/14/2023
#2
要更改 的 URL 路径(换句话说,将请求重新路由到其他终结点),只需在处理请求之前修改中间件中的值即可,如本答案的选项 3 所示。如果您的 API 端点包含路径参数(例如,),那么您希望查看有关如何从对象中提取此类路径的答案,然后将其与预定义的 列表进行比较,如下所示。request
request.scope['path']
'/users/{user_id}'
request
routes_to_reroute
至于更新请求标头或向请求添加新的自定义标头,您可以遵循与此处描述的方法类似的方法,该方法演示了如何修改值。request.scope['headers']
工作实例
如果您希望避免维护要重新路由的路由列表并在中间件中执行检查,则可以改为挂载一个子应用程序,该子应用程序将仅包含需要重新路由的路由,并将中间件添加到该子应用程序,类似于此答案的选项 3。
from fastapi import FastAPI, Request
app = FastAPI()
routes_to_reroute = ['/']
@app.middleware('http')
async def some_middleware(request: Request, call_next):
if request.url.path in routes_to_reroute:
request.scope['path'] = '/welcome'
headers = dict(request.scope['headers'])
headers[b'custom-header'] = b'my custom header'
request.scope['headers'] = [(k, v) for k, v in headers.items()]
return await call_next(request)
@app.get('/')
async def main():
return 'OK'
@app.get('/welcome')
async def welcome(request: Request):
return {'msg': 'Welcome!', 'headers': request.headers}
评论
0赞
Aniket Tiratkar
3/14/2023
这看起来不错,我认为它会起作用,但不符合我的要求(在原始问题中没有提到)。可能是因为我试图将请求重新路由到其他服务器吗?我尝试用此语句更改服务器,但它没有离开服务器。你知道这里可能出了什么问题吗?request.scope['server'] = (host, int(port))
0赞
Chris
3/14/2023
对于将请求重定向/转发到其他服务器,您可以继续使用(但它不允许您将标头传递给其他服务器 - 请参阅此答案,以及此答案和此答案以获取更多详细信息;除非请求是在前端使用 JS 发出的,这将允许您解决此问题 - 请参阅此处)...RedirectResponse
0赞
Chris
3/14/2023
....或将请求转发到其他服务器,类似于此答案中演示的方法。
1赞
Aniket Tiratkar
3/15/2023
非常感谢这些链接,它准确地给了我我需要的信息。我同意你对这个问题的建议,我将保持原样。
评论
localhost