Python requests: 실제 동작하는 토큰 갱신과 안전한 오류 처리

English version

TECH INSIGHT / EXPLAINED

통신 실패·HTTP 상태·인증·JSON 해석을 서로 다른 경계로 다룹니다. 인증 분기에 실제로 도달할 수 있어야 하고 주문 생성을 자동 반복해서는 안 됩니다.

세 사람이 인증 갱신·호출 제한 대기·응답 검사를 구분합니다.
AI로 제작한 설명용 일러스트. 세 사람이 인증 갱신·호출 제한 대기·응답 검사를 구분합니다.

실제 프로젝트의 로컬 실행 화면

기존 프로젝트의 화면 또는 함수를 로컬에서 실행해 촬영했습니다. 개인정보 없는 샘플 입력을 사용했으며, 실행한 범위는 각 이미지 아래에 설명했습니다.

LLMStockTrading의 원본 KISClient._parse를 가상 Response 객체로 직접 실행한 결과. HTTP 오류·업무 오류·JSON 해석 오류가 서로 다른 예외로 관측됐다. 실제 KIS 요청이나 토큰 갱신·주문을 실행한 기록은 아니다.
LLMStockTrading의 원본 KISClient._parse를 가상 Response 객체로 직접 실행한 결과. HTTP 오류·업무 오류·JSON 해석 오류가 서로 다른 예외로 관측됐다. 실제 KIS 요청이나 토큰 갱신·주문을 실행한 기록은 아니다.

타임아웃은 전체 초시계가 아니다

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

댓글