본문 바로가기

개발하자

fastapi(starlette) RedirectResponse 대신 post로 리디렉션 메서드 가져오기

반응형

fastapi(starlette) RedirectResponse 대신 post로 리디렉션 메서드 가져오기

RedirectResponse 개체를 반환한 후 이상한 리디렉션 동작이 발생했습니다.

events.py

router = APIRouter()

@router.post('/create', response_model=EventBase)
async def event_create(
        request: Request,
        user_id: str = Depends(get_current_user),
        service: EventsService = Depends(),
        form: EventForm = Depends(EventForm.as_form)
):
    event = await service.post(
       ...
   )
    redirect_url = request.url_for('get_event', **{'pk': event['id']})
    return RedirectResponse(redirect_url)


@router.get('/{pk}', response_model=EventSingle)
async def get_event(
        request: Request,
        pk: int,
        service: EventsService = Depends()
):
    ....some logic....
    return templates.TemplateResponse(
        'event.html',
        context=
        {
            ...
        }
    )

라우터.파이의

api_router = APIRouter()

...
api_router.include_router(events.router, prefix="/event")

이 코드는 결과를 반환합니다.

127.0.0.1:37772 - "POST /event/22 HTTP/1.1" 405 Method Not Allowed

알겠습니다, 어떤 이유에서인지 GET 요청 대신 POST 요청이 호출되는 것 같습니다. 설명을 검색하면 RedirectResponse 개체가 기본적으로 코드 307로 설정되고 POST를 호출합니다.

나는 조언을 따르고 상태를 추가한다.

redirect_url = request.url_for('get_event', **{'pk': event['id']}, status_code=status.HTTP_302_FOUND)

그리고 get

starlette.routing.NoMatchFound

실험을 위해, 나는 다음으로 바꿀 것이다.

리다이렉트는 성공적으로 완료되지만 포스트 요청은 여기에 적합하지 않습니다. 내가 뭘 잘못하고 있는 거야?

업디

논리 실행을 위한 html 형식

기지를 두다

<form action="{{ url_for('event_create')}}" method="POST">
...
</form>

밑면의파이의

@router.get('/', response_class=HTMLResponse)
async def main_page(request: Request,
                    activity_service: ActivityService = Depends()):
    activity = await activity_service.get()
    return templates.TemplateResponse('base.html', context={'request': request,
                                                            'activities': activity})



POST 후 GET로 리디렉션하려면 다음과 같이 코드를 업데이트하는 것이 좋습니다.

    # ...
    return RedirectResponse(redirect_url, status_code=303)

눈치채셨겠지만...

완전히 작동하는 예:

from fastapi import FastAPI, APIRouter, Request
from fastapi.responses import RedirectResponse, HTMLResponse


router = APIRouter()

@router.get('/form')
def form():
    return HTMLResponse("""
    <html>
    <form action="/event/create" method="POST">
    <button>Send request</button>
    </form>
    </html>
    """)

@router.post('/create')
async def event_create(
        request: Request
):
    event = {"id": 123}
    redirect_url = request.url_for('get_event', **{'pk': event['id']})
    return RedirectResponse(redirect_url, status_code=303)


@router.get('/{pk}')
async def get_event(
        request: Request,
        pk: int,
):
    return f'<html>oi pk={pk}</html>'

app = FastAPI(title='Test API')

app.include_router(router, prefix="/event")

실행, 설치 및 실행 방법:

uvicorn --reload --host 0.0.0.0 --port 3000 example:app

그런 다음 브라우저에서 http://localhost:3000/event/form을 가리킵니다.




예를 들어 를 통해 엔드포인트에 액세스하려고 하기 때문에 언급한 오류가 발생합니다. 그러나 루트가 요청을 처리하기 때문에 요청은 (정수 대신 문자열을 전달하기 때문에) 엔드포인트에 도달합니다.

따라서 예를 들어 엔드포인트에 요청을 제출하려면 가 필요합니다. 다음은 에 있는 HTML에 액세스하는 데 사용할 수 있는 작업 예입니다(원하는 대로 포트 번호를 조정). 요청을 전송하면 이 요청이 트리거됩니다.

@tiangolo가 언급한 바와 같이, 요청 경로에서 요청 경로로 a를 수행할 때, to. 예:

return RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER) 

작업 예:

from fastapi import APIRouter, FastAPI, Request, status
from fastapi.responses import RedirectResponse, HTMLResponse

router = APIRouter()

# This endpoint can be accessed at http://127.0.0.1:8000/event/
@router.get('/', response_class=HTMLResponse)
def event_create_form(request: Request):
    return """
    <html>
       <body>
          <h1>Create an event</h1>
          <form method="POST" action="/event/create">
             <input type="submit" value="Create Event">
          </form>
       </body>
    </html>
    """
    
@router.post('/create')
def event_create(request: Request):
    event = {"id": 1}
    redirect_url = request.url_for('get_event', **{'pk': event['id']})
    return RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER)    

@router.get('/{pk}')
def get_event(request: Request, pk: int):
    return {"pk": pk}


app = FastAPI()
app.include_router(router, prefix="/event")

반응형