파이썬 requests POST가 GET으로 바뀔 때 확인하는 순서

파이썬 requests.post() 뒤에 GET이 발생하면 먼저 302·303 리다이렉트와 자동 추적 여부를 확인합니다. 결과 페이지 조회라면 303과 GET 전환이 설계에 맞을 수 있고, POST 메서드와 본문을 유지해야 한다면 307·308 의미를 서버와 확인해야 합니다. allow_redirects=False로 최초 응답을 분리해 보고, 자동 추적을 허용할 때는 Response.history와 response.request.method를 함께 기록하면 최종 200에 가려진 요청 흐름을 검증할 수 있습니다.

왜 POST 뒤에 GET이 추가될까요?

requests.post()를 호출했는데 서버 로그에는 POST 다음 GET이 보이면, 처음부터 requests가 GET을 보낸 것으로 단정하기 어렵습니다. 서버가 Location 헤더와 함께 리다이렉트 응답을 보냈고, 클라이언트가 그 응답을 따라간 흐름일 수 있습니다.

Requests는 HEAD를 제외한 메서드에서 기본적으로 Location 리다이렉트를 자동 처리합니다. 따라서 서버가 302를 반환하면 라이브러리가 다음 URL로 이동하고, 그 과정에서 POST가 GET으로 바뀔 수 있습니다. 마지막 응답이 200이어도 그것은 최종 URL에서 받은 응답일 뿐, POST 본문이 원래 의도대로 처리됐다는 뜻은 아닙니다.

먼저 자동 추적을 멈추고 최초 응답을 확인하면 원인을 좁히기 쉽습니다. 아래 코드의 주소와 입력값은 설명을 위한 예시이므로, 실행할 때는 권한이 있는 테스트 대상에 맞게 바꿔야 합니다.

import requests

response = requests.post(
    "https://example.com/submit",
    data={"name": "홍길동"},
    allow_redirects=False,
)

print(response.status_code)
print(response.headers.get("Location"))

이 요청에서 302, 303, 307 또는 308 상태와 Location이 보이면, 다음 URL로 이동하라는 서버의 지시를 받은 것입니다. 이 단계에서는 최종 페이지의 내용보다 최초 응답의 상태 코드와 이동 대상이 더 중요합니다.

자동 리다이렉트가 실제로 어떻게 진행됐는지 확인하기

자동 추적이 필요한 흐름이라면 최종 응답만 저장하지 말고 리다이렉트 이력을 함께 남기는 편이 안전합니다. Response.history에는 리다이렉트를 처리하기 위해 거친 응답이 오래된 순서부터 들어갑니다. response.request는 해당 응답을 만들 때 실제로 사용된 요청이므로, 최종 메서드와 URL을 확인하는 데 사용할 수 있습니다.

import requests

response = requests.post("https://example.com/submit", data={"name": "홍길동"})

print("final status:", response.status_code)
print("final url:", response.url)
print("final method:", response.request.method)

for index, previous in enumerate(response.history, start=1):
    print(
        index,
        previous.status_code,
        previous.request.method,
        previous.headers.get("Location"),
    )

이 로그에서 첫 응답이 302 또는 303이고 최종 response.request.method가 GET이라면, POST 이후에 GET으로 전환된 흐름을 확인한 것입니다. 3xx는 추가 동작이 필요하다는 뜻이므로 최종 상태 코드 하나만으로 원래 POST의 처리 결과를 판단할 수 없습니다.

다만 최종 메서드가 POST라고 해서 서버가 본문을 정확히 처리했다는 사실까지 자동으로 입증되는 것은 아닙니다. 중요한 API 명령이나 업로드라면 서버 측 수신 기록, 요청 식별자, 또는 별도 결과 조회로 본문 처리 여부를 확인해야 합니다.

302·303·307·308의 차이

리다이렉트 상태 코드는 비슷해 보여도 다음 요청의 의미가 다릅니다.

  • 302 Found: 역사적인 호환성 때문에 사용자 에이전트가 POST를 GET으로 바꾸어 리다이렉트할 수 있습니다.
  • 303 See Other: POST 처리 결과를 다른 리소스에서 조회하게 하는 용도입니다. 일반적으로 다음 요청을 GET 또는 HEAD로 전환합니다.
  • 307 Temporary Redirect: 자동으로 따라갈 때 요청 메서드를 바꾸면 안 됩니다.
  • 308 Permanent Redirect: 영구 리다이렉트이며, 307과 같이 메서드를 보존하는 의미를 가집니다.

따라서 선택 기준은 다음처럼 정리할 수 있습니다.

결과 화면을 보여주는 흐름

폼 제출 뒤 결과 페이지를 조회하는 것이 목적이라면 POST의 처리와 결과 조회를 분리하는 303 흐름이 자연스럽습니다. 반대로 302에 의존하면 클라이언트별 동작 차이를 해석하기가 어려워질 수 있습니다.

메서드와 본문이 이어져야 하는 흐름

결제·업로드·API 명령처럼 다음 요청에도 메서드와 본문이 필요하다면 서버가 307 또는 308을 반환하도록 설계했는지 확인해야 합니다. 307과 308의 선택은 임시 주소 변경인지 영구 주소 변경인지에 달려 있습니다.

이때 307·308이 메서드를 보존한다는 의미와 실제 서버가 본문을 받아 처리했다는 결과는 구분해야 합니다. 운영 로그에서 최종 URL과 메서드만 기록하지 말고, 요청을 식별할 수 있는 값과 서버 처리 결과도 함께 연결하는 편이 좋습니다.

운영 코드에서 어떤 검증을 남길까요?

자동 리다이렉트를 허용할지 여부는 흐름의 목적에 따라 결정하면 됩니다.

import requests

response = requests.post(
    "https://example.com/command",
    json={"action": "refresh"},
)

redirects = [
    {
        "status": item.status_code,
        "method": item.request.method,
        "url": item.url,
        "location": item.headers.get("Location"),
    }
    for item in response.history
]

request_summary = {
    "status": response.status_code,
    "url": response.url,
    "method": response.request.method,
    "redirects": redirects,
}
print(request_summary)

결과 페이지가 필요하고 서버의 303 설계가 확인된 경우라면 기본 자동 리다이렉트를 사용할 수 있습니다. 반면 POST 데이터가 사라졌는지 조사하거나, 리다이렉트 대상이 예상한 주소인지 확인해야 한다면 allow_redirects=False로 최초 응답을 분리하는 것이 먼저입니다.

특히 다음과 같은 기록을 남기면 장애 분석이 쉬워집니다.

  • 최초 요청의 의도와 대상 URL
  • Response.history에 담긴 각 상태 코드와 Location
  • 최종 response.request.method와 URL
  • 서버가 반환한 업무 결과 또는 오류 식별자

인증이나 재시도 정책은 리다이렉트 메서드 문제와 별도의 검토 대상입니다. 이 글의 범위에서는 먼저 요청이 어느 상태 코드에서 어떤 메서드로 이어졌는지 확인하고, 그 다음에 인증·재시도 정책을 따로 점검하는 순서가 안전합니다.

정리: 최종 200보다 요청 흐름을 먼저 보세요

파이썬 requests.post() 뒤에 GET이 발생하면 먼저 302·303 리다이렉트와 자동 추적 여부를 확인합니다. 결과 페이지 조회라면 303과 GET 전환이 설계에 맞을 수 있고, POST 메서드와 본문을 유지해야 한다면 307·308 의미를 서버와 확인해야 합니다.

allow_redirects=False로 최초 응답을 확인한 뒤, 자동 추적을 사용할 때는 response.history와 response.request.method를 기록해 보십시오. 최종 200만 보고 성공으로 기록하지 말고, 원래 POST가 어떤 리다이렉트를 거쳐 어떤 요청으로 처리됐는지까지 확인해야 다음 조치를 정확히 선택할 수 있습니다.

다음으로 확인할 질문

  • 서버가 결과 페이지 조회를 의도한 것인지, POST 본문 보존을 의도한 것인지 먼저 정했나요?
  • 리다이렉트 대상 URL과 최종 요청 메서드를 로그에서 확인할 수 있나요?
  • 본문 처리가 중요한 요청이라면 서버 측 처리 결과까지 연결해 검증했나요?

참고 자료: Requests Quickstart — Redirection, Requests Advanced Usage, RFC 9110: HTTP Semantics

Leave a Comment