미들웨어 Body 스트림 재사용 문제 해결 #556
sgoldenbird
started this conversation in
Trouble Shooting
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
🐞 문제 상황 (Problem Description)
Next.js 미들웨어에서 accessToken 갱신을 위해 fetch 요청을 재시도할 때, request.body 스트림을 재사용할 수 없어 TypeError: Body has already been used 에러가 발생했습니다. 이 문제는 401 Unauthorized 에러에 대한 자동 복구 로직을 구현하는 것을 방해했습니다.
💻 환경 정보 (Environment)
🔍 발생 원인 분석 (Investigation)
스트림(Stream)의 개념
스트림은 데이터가 한 번에 모두 로드되지 않고, 시간이 지남에 따라 순차적으로 전달되는 구조입니다. 쉽게 말해, 파일을 다운로드할 때 전체 파일이 다 받아질 때까지 기다리는 것이 아니라, 데이터가 들어오는 대로 처리하는 것과 같습니다. 예를 들어 영화 스트리밍처럼 파일 전체를 다운로드하지 않고도 일부 데이터가 준비되면 바로 재생할 수 있습니다.
ReadableStream의 일회성
ReadableStream은 데이터를 한 번만 읽을 수 있는 스트림입니다.이는 데이터가 전달된 후에는 스트림이 비워지기 때문에 다시 읽을 수 없다는 뜻입니다.
Request Body와 스트림
Next.js 미들웨어에서 request.body 역시 ReadableStream 형태입니다. 따라서 미들웨어에서 fetch를 통해 요청 본문을 한 번 읽어 백엔드로 전달하면, 스트림이 소비되어 이후 재사용이 불가능합니다.
충돌 지점
미들웨어는 401 Unauthorized 발생 시 refreshToken으로 accessToken을 갱신하고 원래 요청을 재시도하려 했습니다. 하지만 최초 요청에서 request.body가 이미 소비되었기 때문에, 두 번째 요청에서 다시 body를 사용하려 하면 TypeError: Body has already been used 에러가 발생했습니다.
🛠 시도해본 해결 방법 (Attempts)
❌ 스트림 복사 시도: request.clone()과 같은 방법으로 요청 객체를 복사하려 했으나, 스트림 자체의 복제 문제와 미들웨어 환경의 제약으로 인해 실패했습니다.
❌ 로직 단순화: 401 에러 시 무조건 클라이언트로 리디렉션하는 방식으로 회귀했으나, 이는 refreshToken의 자동 갱신을 통한 사용자 경험 개선이라는 원래의 목표에 맞지 않았습니다.
✅ 최종 해결 방법 (Final Solution)
일회성 스트림의 내용을 미리 문자열로 복사해두고, 필요할 때마다 복사본을 사용하는 방식으로 문제를 해결
request.body를 fetch로 포워딩하기 전에 await request.text()를 사용하여 스트림의 내용을 문자열로 미리 읽어 별도의 변수에 저장하는 방법을 사용했습니다. 이후 1차 fetch 요청과 401 에러 시의 재시도 요청 모두 이 저장된 rawBody 변수를 body로 사용하여 문제를 해결했습니다.
💡 알게 된 점 (Lessons Learned)
Beta Was this translation helpful? Give feedback.
All reactions