- 분야: BE
- 기술 스택: TypeScript · vinext · Vite · Web Request API
문제와 원인
vinext 요청 파이프라인은 URL을 재작성하면서 원본 Request를 새 Request의 초기값으로 전달했다. 첫 재작성 요청의 본문을 읽으면 원본도 bodyUsed=true가 돼, 같은 원본으로 두 번째 Request를 생성할 때 TypeError가 발생했다.
수정 전 코드
URL 재작성
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
cloned = new Request(url, request);
수정 후 코드
preserveVinextRequestBodies 변환 결과
본문이 있고 아직 소비되지 않은 Request를 먼저 clone()한 뒤 복제본을 URL 재작성에 사용한다. 원본 본문은 다음 라우트 단계에서 읽을 수 있도록 보존한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const requestInitSource = request.body && !request.bodyUsed
? request.clone()
: request;
cloned = new Request(url, requestInitSource);
transform
빌드 플러그인은 대상 vinext 모듈에서 기존 복사식이 정확히 1개일 때만 변환한다. 0개나 2개면 내부 구현이 달라졌다는 오류로 빌드를 중단한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const occurrences = code.split(UNSAFE_REQUEST_COPY).length - 1;
if (occurrences !== 1) {
throw new Error(
`Unsupported vinext request pipeline: expected one unsafe Request copy, found ${occurrences}.`,
);
}
검증 결과
재현 입력은 UTF-8 25 B의 POST JSON이다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
{"action":"submit","n":1}
Node.js에서 같은 25 B JSON으로 수정 전 복사식과 빌드 플러그인이 변환한 복사식을 각각 두 차례 실행했다. Cloudflare Wrangler의 로컬 Worker에서도 같은 복사식의 본문 보존 결과를 재현했다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
| 비교 항목 | 수정 전 | 수정 후 |
|---|---|---|
| 첫 재작성 요청 본문 | 25 B, 입력과 일치 | 25 B, 입력과 일치 |
첫 본문 읽기 후 원본 bodyUsed | true | false |
| 원본으로 두 번째 Request 생성·본문 읽기 | TypeError | 성공, 25 B와 전체 문자열 일치 |
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
| 플러그인 입력 | 결과 |
|---|---|
| 다른 모듈 경로 | 변환 건너뜀 |
| 대상 모듈에 기존 복사식 0개 | 변환 거부 |
| 대상 모듈에 기존 복사식 2개 | 변환 거부 |