Python requests: 실제 동작하는 토큰 갱신과 안전한 오류 처리
TECH INSIGHT / EXPLAINED
통신 실패·HTTP 상태·인증·JSON 해석을 서로 다른 경계로 다룹니다. 인증 분기에 실제로 도달할 수 있어야 하고 주문 생성을 자동 반복해서는 안 됩니다.
실제 프로젝트의 로컬 실행 화면
기존 프로젝트의 화면 또는 함수를 로컬에서 실행해 촬영했습니다. 개인정보 없는 샘플 입력을 사용했으며, 실행한 범위는 각 이미지 아래에 설명했습니다.
타임아웃은 전체 초시계가 아니다
Requests에는 기본 타임아웃이 없습니다. timeout=(3,10)은 연결과 읽기 무응답 대기 한도를 설정하며, 전체 본문을 10초 안에 받는다는 보장이 아닙니다. 바이트가 계속 도착하면 더 오래 걸릴 수 있습니다. 개별 요청 제한 외에 작업 전체 시간 예산도 두세요.
401을 예외로 던지기 전에 처리
예제는 인증 규약이 이를 허용하는 신뢰된 조회 API에서만 한 번 갱신합니다. raise_for_status 이전에 401을 확인하고 첫 응답을 닫은 뒤 새 토큰으로 한 번 더 요청합니다. 두 번째 401은 정상적으로 예외가 됩니다. 403은 권한 부족일 수 있으므로 무조건 갱신하지 않습니다.
def authenticated_get_json(session, url, token, refresh_token):
# For a trusted read-only API whose contract permits one 401 refresh.
for attempt in range(2):
response = session.get(url,
headers={'Authorization': 'Bearer ' + token},
timeout=(3, 10), allow_redirects=False)
try:
if response.status_code == 401 and attempt == 0:
needs_refresh = True
else:
if not 200 <= response.status_code < 300:
response.raise_for_status()
raise RuntimeError('unexpected non-success status')
return response.json()
finally:
response.close()
if needs_refresh:
token = refresh_token() # returns a new token, exactly once
raise RuntimeError('unreachable')반복 가능한 작업에서만 재시도
안전한 조회에는 일부 연결 실패·429·일시적 5xx에 제한된 백오프와 지터를 적용할 수 있습니다. Retry-After의 초와 HTTP 날짜를 모두 존중하고 전체 마감이나 시도 예산이 끝나면 멈춥니다. 서버가 요청한 대기를 임의로 짧게 잘라서는 안 됩니다.
주문 POST의 타임아웃은 접수 후 응답만 놓친 상태일 수 있습니다. 문서화된 식별자로 조회·대조한 다음 재제출을 결정하세요. 이 차이를 숨기는 범용 retry(method,url)는 예제에 넣지 않았습니다.
JSON과 스키마도 별도 검사
2xx 응답이 잘못된 JSON이나 다른 스키마를 담을 수 있습니다. 앱이 대응할 수 있는 경계에서 해석 오류를 처리하고 필수 키·타입·값의 범위를 검사합니다. 모든 응답 앞 200자를 로그로 남기면 개인정보나 비밀이 들어갈 수 있습니다. 상태·엔드포인트 별칭·콘텐츠 유형·본문 길이·정제한 오류 코드를 우선하세요.
실서버 없이 네 경로를 검증합니다. 401→200은 한 번 갱신, 401→401은 중단, 403은 갱신 없음, 잘못된 JSON을 가진 200은 해석 오류 전달입니다. 성공한 실요청만으로는 확인하지 못하는 제어 흐름입니다.
공식 자료와 함께 읽기
Requests timeout behavior · HTTP semantics · 호출 제한과 재시도
내용·예제 검토: 2026-09-29
댓글
댓글 쓰기