python - 使用 aiohttp 将 fastapi.Request 转发到另一个 API
问题描述
动机
我正在构建一个执行授权检查的 API 网关,使用 Cloud Run 托管在 GCP 上。
在函数authorize_request
中,我想使用 aiohttp 获取一个fastapi.Request
对象,将其转发到不同的 API,然后以 a 形式返回响应fastapi.responses.JSONResponse
——保留有效负载、标头和状态码。
问题
是我使用字典将方法字符串映射到函数的方法吗?Pythonic 和/或推荐?有没有更简单的方法?
我是否保留了可以合理预期的请求/响应的所有字段,并且做得正确?我注意到那里还有其他字段,例如
request.proxy
,request.cookies
,但我认为这些与简单的 API 无关。我错了吗?不包含这些字段会导致 GCP 身份验证出现问题。ETC?
import aiohttp
import asyncio
from typing import Callable
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
async def authorize_request(request: Request, base_url: str) -> JSONResponse:
""" Forward a request (if authorized)
Arguments
---------
request
the request to forward
base_url
the base url of the new domain to forward the request to
Returns
-------
response
the response generated after the request was forwarded
"""
# Some authorization checks on the request bearer token take place here, but
# have been omitted since they aren't relevant
# Forward the request
# I'm aware that I shouldn't be creating a session for each request, this is
# a minimal example, and the session will be created/destroyed elsewhere
async with aiohttp.ClientSession() as session:
# Find the right function for the method in the request.
# You might notice that I'm not raising a fastapi.HTTPException here.
# This is intentional, since I'm capturing the request object using
# fastapi.middleware, and the relevant decorator doesn't handle these
# exceptions gracefully as it otherwise might
methods = {
'delete': session.delete,
'get': session.get,
'head': session.head,
'options': session.options,
'patch': session.patch,
'post': session.post,
'put': session.put
}
if request.method not in methods:
message = f"method '{request.method}' not supported"
return JSONResponse(status_code=400, content={'message': message})
method = methods[request.method]
# Make the request
new_url = f'{base_url}{request.url.path}'
response = await method(new_url,
data=request.body,
headers=request.headers)
# Return the response
return JSONResponse(status_code=str(response.status),
content=response.json)
@app.middleware('http')
async def authorize(request: Request, _call_next: Callable):
""" Catch and process incoming requests
Arguments
---------
request
the request to authorize and potentially forward
"""
new_url = 'http://some-other-domain.com/api-name'
return await authorize_request(request, new_url)
解决方案
推荐阅读
- linux - Azure Pipelines、托管 Ubuntu 代理和带有 PowerShell Core 的 Azure CLI 任务:使用 Az 模块并正确进行身份验证
- react-native - 反应原生 | 华为应用图库服务?
- reactjs - 为 mousedown 和 touchstart 事件反应 TypeScript 类型"
- c - 计算多项式函数时的返回值问题
- javascript - 从 FileReader.readAsArrayBuffer() 创建文件
- python - 如何以 ['2020-05-27 15:26:57', '2020-05-22 16:40:58'] 的格式将日期和时间从最旧到最新排序?
- javascript - 通过Ajax更新页面内容只进行一次
- mongodb - mongoDB $set 使用文档键值/其他字段值的问题
- json - 小写 JSON 中的值
- linux - 为什么 Anaconda 中的 scikit-learn 在“validation_curve”类型签名中显示 cv="warn"?