我已在 aws s3 存储桶中部署了静态站点,其 URL 如下所示 -
https://{bucket_name}.s3.{zone}.amazonaws.com/website/{ID}/index.html
我想重定向所有进入服务器的流量,应该像这样转发到 s3 存储桶中 -
username.localhost:9000 -> https://{bucket_name}.s3.{zone}.amazonaws.com/website/{username}/index.html
如果您对nginx有任何建议请分享
我已经尝试过解决方案 -
import uvicorn
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
import httpx
import boto3
app = FastAPI()
S3_BUCKET_NAME = ${bucket}
async def proxy_request(request: Request):
s3_client = boto3.client('s3')
# Construct the S3 object key based on your requirements
x = request.url.path.split("/")[-2:]
y = '/'.join(x)
s3_key = f"website/{y}"
try:
# Get the object from S3
response = s3_client.get_object(Bucket=S3_BUCKET_NAME, Key=s3_key)
except s3_client.exceptions.NoSuchKey:
raise HTTPException(status_code=404, detail="Object not found")
# Return the S3 object's content back to the client
return StreamingResponse(
content=response['Body'].iter_chunks(),
status_code=200,
headers={"Content-Type": response['ContentType']},
)
@app.middleware("http")
async def proxy_middleware(request: Request, call_next):
try:
return await proxy_request(request)
except HTTPException as exc:
return exc
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=9000)
您要求的解决方案彼此根本不同。您的摘要说代理,但描述说重定向。此外,您的本地主机 URL 有一个子域,仅当您将其映射到主机条目文件中时才可用。我将尝试涵盖 localhost 到 s3 重定向/转发的用例。
如果您想要的只是一个简单的重定向,
@app.route('/{_:path}')
async def s3_redirect(request: Request) -> RedirectResponse:
# return RedirectResponse(request.url.replace()) # If you want to retain the path/query params
return RedirectResponse("https://{bucket_name}.s3.{zone}.amazonaws.com/website/{username}/index.html")
如果您正在寻找 nginx 的解决方案,以下配置应该可以解决问题
server {
listen 9000;
location / {
proxy_pass {s3_website};
}
# more locations to different endpoints
}
如果用例只是代理,我更喜欢 nginx 或等效的代理应用程序而不是使用 FastAPI。 但是,如果您仍然想使用 FastAPI,我会使用一种有点广泛的解决方案,如下所示。以下示例将充当基本代理服务。您不需要检查存储桶对象,因为 httpx 客户端会为您处理这些事情。
请注意,您的存储桶对象应该可以公开访问才能使用此解决方案。
import logging
from http import HTTPStatus
import httpx
import uvicorn.logging
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.routing import APIRoute
TARGET_URL = "http://127.0.0.1:8080" # Change this to the URL you want to proxy requests to
async def proxy(request: Request) -> Response:
"""Proxy handler function to forward incoming requests to a target URL.
Args:
request: The incoming request object.
Returns:
Response: The response object with the forwarded content and headers.
"""
try:
async with httpx.AsyncClient() as client:
body = await request.body()
# noinspection PyTypeChecker
response = await client.request(
method=request.method,
url=TARGET_URL + request.url.path,
headers=dict(request.headers),
cookies=request.cookies,
params=dict(request.query_params),
data=body.decode(),
)
# If the response content-type is text/html, we need to rewrite links in it
content_type = response.headers.get("content-type", "")
if "text/html" in content_type:
content = response.text
# Modify content if necessary (e.g., rewriting links)
# content = modify_html_links(content)
else:
content = response.content
response.headers.pop("content-encoding", None)
return Response(content, response.status_code, response.headers, content_type)
except httpx.RequestError as exc:
logging.getLogger("uvicorn.error").error(exc)
raise HTTPException(status_code=HTTPStatus.BAD_GATEWAY.value, detail=HTTPStatus.BAD_GATEWAY.phrase)
if __name__ == '__main__':
uvicorn.run(
app=FastAPI(
routes=[
APIRoute("/{_:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], endpoint=proxy)
]
)
)