콘텐츠로 이동

요청 흐름

이 페이지는 메서드 하나를 호출했을 때 라이브러리 안에서 일어나는 일을 순서대로 설명합니다. 각 단계는 코레일+ 안드로이드 앱 7.0.8에서 확인한 계약을 기준으로 합니다.

요청 흐름 요청 흐름

1. 요청 만들기

메서드에 넘긴 값은 앱이 쓰는 요청 형식(폼)으로 바뀝니다.

  • 필드 순서: 앱은 요청 객체(DTO)에 선언된 순서대로 필드를 보냅니다. 라이브러리도 같은 순서로 폼을 만듭니다. 목록 값은 txtSeatNo1, txtSeatNo2처럼 1부터 번호를 붙입니다.
  • 공통 필드: 대부분의 요청은 맨 앞에 Device, Version, AppVersion, Key를 싣습니다. 환불과 환불 수수료 조회만 앱처럼 공통 필드를 맨 뒤에 둡니다.
  • 언어: KorailConfig.lang을 설정하면 Key 다음에 lang을 보냅니다. 설정하지 않으면 보내지 않습니다.
  • 빈 값: 값이 빈 문자열인 필드는 보내지 않습니다. 운임 조회의 상품번호처럼 앱이 빈 값을 그대로 보내는 필드는 예외로 보냅니다.
  • 입력 검사: 카드번호 자릿수, 승객 수, 환승 구간 순서처럼 앱이 화면에서 막는 입력은 요청을 보내기 전에 검사하고 KorailProtocolError를 발생시킵니다.

2. 대기열 통과

다음 메서드는 요청 전에 NetFunnel 대기열을 거칩니다.

reserve_merge, reserve_limousine을 비롯한 그 밖의 메서드는 대기열을 거치지 않습니다. 대기열은 앱과 같은 순서로 진행합니다.

  1. 대기열 서버에 입장 키를 요청합니다(5101).
  2. 대기가 필요하다는 응답(201, 202)이면 서버가 알려 준 시간만큼 기다린 뒤 다시 확인합니다(5002). 대기 시간은 1~30초로 제한합니다.
  3. 통과하면 KORAIL API에 요청을 보냅니다.
  4. 요청이 끝나면 성공·실패와 관계없이 입장 키를 반납합니다(5004).

관문은 두 종류입니다.

관문 쓰는 곳 대기열 서버 오류 시
inquiry, peak_season_inquiry, product_inquiry 열차 조회 대기열을 건너뛰고 요청을 보냅니다.
reserve, pay, reservation_view 예약(reserve, reserve_transfer, reserve_with_discount_card), 카드 결제, 예약 내역 조회 요청을 보내지 않고 예외를 발생시킵니다.

대기열 서버가 요청을 차단하면(301, 302) KorailQueueRejectedError가 발생합니다. 입장 키는 대기열 서버와만 주고받으며 KORAIL API 요청에는 싣지 않습니다. 대기열 설정은 설정을 참고하세요.

3. 전송

  • 헤더: API 요청은 앱과 같은 User-Agent: korailtalk에 Connection: Keep-Alive, Accept-Encoding: gzip을 보내고 Accept는 보내지 않습니다. 대기열 요청은 앱의 대기열 SDK처럼 안드로이드 기본 User-Agent(Dalvik/2.1.0 (...))를 사용하며, 본문이 빈 POST로 보냅니다.
  • DynaPath: 로그인, 열차 조회, 운임 조회, 예약처럼 앱이 보호하는 경로에는 DynaPath 토큰 헤더를 붙입니다. 기본값으로 켜져 있습니다.
  • 로그인 비밀번호: 서버에서 받은 암호화 정보로 AES 암호화한 뒤 보냅니다. 암호화 정보가 없으면 평문으로 보내지 않고 거절합니다.

4. 응답 판정

대부분의 KORAIL 응답에는 공통 상태 필드(이 문서에서는 봉투라고 부릅니다)가 있습니다. 역 목록처럼 봉투가 없을 수 있는 응답도 있습니다.

필드 뜻
strResult SUCC 또는 FAIL
h_msg_cd 결과 코드 (예: IRZ000001)
h_msg_txt 결과 메시지
  • strResult가 FAIL이면 실패입니다. 결과 코드에 따라 KorailAppError의 하위 예외(예: 매진, 결과 없음)를 발생시킵니다.
  • 실패 코드가 P058이면 세션 만료로 보고 KorailSessionExpiredError를 발생시키며, 로컬 세션을 비웁니다.
  • 카드 결제처럼 실패도 정상 응답으로 돌려줘야 하는 메서드는 예외 대신 str_result가 FAIL인 응답 모델을 반환합니다. 각 메서드 설명에 표시했습니다.

5. 응답 읽기

응답은 메서드마다 정해진 dataclass로 바뀝니다. 읽는 규칙은 모든 메서드에 공통입니다.

  • 정수와 문자열: 앱이 문자열로 선언한 필드를 서버가 JSON 정수로 보내는 경우가 있습니다(예: "0001" 대신 1). 이런 값은 str()로 바꿔 "1"로 담으며, 앞자리 0은 복원하지 않습니다. true/false는 정수로 취급하지 않습니다.
  • 선택 필드: 응답에 없거나 null이거나 타입이 맞지 않는 선택 필드는 None입니다. 아래 앱 기본값을 쓰는 필드 18개는 예외입니다.
  • 필수 필드: 다음 요청에 다시 보내야 하는 값(예약 번호, 반환 식별자 등)이 없거나 타입이 틀리면 KorailProtocolError를 발생시킵니다.
  • 원본 보존: 모든 응답 모델의 raw에 서버가 보낸 원본이 그대로 남습니다.

앱 기본값을 쓰는 필드

아래 18개 필드는 다른 선택 필드와 읽는 규칙이 다릅니다.

  • 문자열 필드는 응답에서 빠지면 None 대신 앱과 같은 기본값 ""을 씁니다.
  • 숫자로 바꾸는 필드(h_srcar_no, h_rest_seat_cnt, st_loc_rt, cls_loc_rt)는 빠지거나 ""이면 None입니다.
  • 18개 필드 모두 값이 null이거나 타입이 맞지 않으면 None으로 바꾸지 않고 KorailProtocolError를 발생시킵니다.
위치 필드 개수
역 목록 stn_cd, stn_nm 2
호차·좌석 속성 h_srcar_no, h_rest_seat_cnt, h_psrm_cl_nm, seatAttNm 4
좌석 배치 layout_type, seat_ary_cd 2
좌석 seat_no, sale_psb_flg, dir_seat_att_cd, rq_seat_att_cd, seat_spec, sqr_no, intg_msg_cd, intg_msg 8
창문 위치 st_loc_rt, cls_loc_rt 2

6. 실패했을 때

  • 응답을 읽지 못하면 KorailProtocolError 등의 예외를 발생시킵니다. 예외의 raw에는 서버가 보낸 응답 전체가, parser_raw에는 읽다가 멈춘 부분이 들어 있습니다.
  • 예약·결제·환불 같은 변경 요청은 자동으로 다시 보내지 않습니다. 응답을 읽지 못했어도 서버에서는 이미 처리됐을 수 있기 때문입니다. 이때는 예외의 raw를 먼저 확인하고, 예약은 get_reservation_history(), 결제·환불은 get_ticket_list()로 결과를 확인한 뒤에 다시 호출할지 정하세요.

앱과 다르게 처리한 부분

다음 동작은 앱과 다르게 라이브러리가 정한 것입니다.

  • 로그인 확인: 로그인이 필요한 메서드를 로그인하지 않은 상태에서 호출하면 요청을 보내지 않고 KorailAuthError를 발생시킵니다. 앱에는 없는 검사입니다.
  • 로그인 암호화 정보: 앱은 앱을 시작할 때 받아 둔 암호화 키를 쓰고, 키가 비어 있을 때만 다시 받습니다. 라이브러리는 로그인할 때마다 새로 받습니다.
  • 0원 결제: 앱은 결제할 금액이 0원이면 카드 없이 발권을 요청합니다. 라이브러리는 이 경로를 구현하지 않으며, 0원 홀드를 pay_with_card로 결제하려고 하면 요청 전에 거절합니다.
  • 환승 조회 전환: search_trains_with_transfer_fallback은 직통 열차가 없다는 결과 코드(WRD000061)를 받으면 같은 조건으로 환승 조회 첫 페이지를 받습니다. 앱과 달리 확인 창을 띄우거나 열차군을 바꾸지 않습니다.

확인되지 않은 부분

앱 내부의 일부 값은 공개돼 있지 않아 라이브러리가 확인하지 못했습니다. 항목마다 처리 방식이 다르며, 관련 메서드 설명에 표시했습니다.

  • 대기열 관문 식별값: 라이브러리의 기본값이 앱의 값과 같은지 확인하지 못했습니다. 기본 조회(inquiry), 예약(reserve), 결제(pay), 예약 내역(reservation_view) 관문에서는 실서버 확인을 마친 메서드의 요청이 이 기본값으로 처리됐습니다. 성수기 조회(peak_season_inquiry)와 특가 상품 조회(product_inquiry) 관문은 실서버에서 확인하지 못했습니다.
  • 성수기 판정: 앱이 출발일을 성수기로 판정하는 기준은 확인하지 못했습니다. 라이브러리에서는 호출자가 peak_season으로 정합니다.
  • DynaPath 차단 판정: 차단 응답을 판정하는 정확한 기준은 확인하지 못했습니다.
  • N카드 할인 코드: reserve_with_discount_card가 보내는 할인 코드는 실서버에서 확인하지 못했습니다.
  • 일부 환불 제어값: 값을 알 수 없는 제어값은 추측하지 않고 요청에서 뺍니다.

메서드별 실서버 확인 여부는 실서버 확인 현황에 있습니다.