← 홈Setup Tip

Setup Tip

Setup Tip — 스트림이 아닌 2xx 응답은 짧은 답이 아니라 오류다

스트리밍 엔드포인트가 성공 코드와 함께 스트림이 아닌 본문을 돌려주면, 클라이언트는 이를 "중간에 끊긴 답"으로 오해하기 쉽다. 본문 유무와 미디어 타입을 먼저 확인하고, 불일치는 재시도하지 않는 전용 오류로 올리며, 상태 코드는 메시지 문구가 아니라 필드로 전달하라.

상황

모델 제공자의 스트리밍 엔드포인트를 부르는 클라이언트가 있다. 정상일 때는 이벤트 스트림이 오고, 클라이언트는 이벤트를 읽어 답을 조립한다. 그런데 어떤 사용자는 답이 몇 글자 만에 끝나거나 아예 비어서 돌아온다고 보고한다. 로그에는 오류가 없고, 상태 코드는 200이다.

흔한 착각

2xx면 성공이고, 성공이면 본문은 스트림이라고 가정한다. 그래서 스트림 파서가 아무 이벤트도 찾지 못하면 "모델이 짧게 답했다"거나 "연결이 중간에 끊겼다"로 처리하고, 끊김으로 분류된 요청은 조용히 재시도된다. 진짜 원인은 어디에도 기록되지 않는다.

실제로 일어난 일

엔드포인트는 성공 코드와 함께 스트림이 아닌 본문, 즉 오류 설명이 담긴 일반 문서를 돌려주고 있었다. 이 불일치를 오류로 올리는 수정을 리뷰하는 동안 자동 리뷰어가 경계 사례를 하나씩 더 찾아냈다. 미디어 타입의 대소문자가 섞인 경우, 본문이 아예 없는 2xx, 본문은 없는데 헤더만 스트림이라고 적힌 2xx, 그리고 오류 메시지에 "HTTP 503" 같은 문구를 넣었더니 다른 계층이 그 문구를 상태 코드로 다시 파싱해 재시도 가능한 전송 오류로 바꿔 버린 경우까지. 수정 하나가 여러 번의 왕복을 거친 이유가 전부 이 경계들이었다.

무엇을 확인해야 하는가

스트림을 파싱하기 전에 두 가지를 먼저 본다. 본문이 실제로 있는가, 그리고 미디어 타입의 본체(파라미터를 뗀 부분)가 대소문자 무관하게 기대한 스트림 타입과 같은가. 둘 중 하나라도 아니면 그 응답은 성공이 아니다. 그리고 그 판단이 이후 계층을 지나면서 바뀌지 않는지, 재시도 분류기가 그 오류를 어떻게 읽는지도 따라가 본다.

고치는 방향

불일치는 전용 오류 타입이나 오류 코드로 올리고, 재시도 대상이 아닌 종단 오류로 분류한다. 진단을 위해 본문 앞부분을 읽되 크기에 상한을 두고, 읽은 뒤 스트림을 취소하며, 인증 토큰 같은 값은 지운다. 상태 코드는 구조화된 필드로 전달하고, 사람이 읽는 메시지 문구에는 다른 코드가 파싱할 만한 패턴을 넣지 않는다.

확인 방법

경계마다 테스트를 하나씩 둔다. 스트림이 아닌 본문의 2xx, 본문 없는 2xx, 헤더만 스트림인 빈 2xx, 대소문자가 섞인 미디어 타입, 상태 코드처럼 보이는 문구가 든 본문. 각 테스트가 수정 전 코드에서는 실패하고 수정 후에는 통과하는지 확인하고, 마지막으로 그 오류가 재시도되지 않고 한 번에 사용자에게 보이는지 본다.