Создайте прокси-сервер в Python (Flask, Fastapi), который будет отображаться в корзине s3

Я развернул статический сайт в корзине 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)


Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
145
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы просите решения, которые фундаментально отличаются друг от друга. В вашем резюме указано прокси, но в описании указано перенаправление. Кроме того, ваш URL-адрес локального хоста имеет поддомен, который можно использовать только в том случае, если он сопоставлен в файле записи вашего хоста. Я постараюсь охватить варианты использования перенаправления/перенаправления 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 попытается достичь конечной точки s3 и ответить соответствующим образом.

Обратите внимание, что для использования этого решения ваши объекты корзины должны быть общедоступны.

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)
            ]
        )
    )

Другие вопросы по теме