---
title: "캐시 효과를 재는데 캐시가 꺼져 있었다, Playwright route()의 함정"
description: "Playwright 는 route 를 하나라도 등록하면 그 컨텍스트의 HTTP 캐시를 끕니다. 캐시 재사용 효과를 재다가 warm 값이 cold 와 같게 나와서 CDP Fetch 로 바꾼 과정을 정리했습니다."
date: 2026-10-30
updated: 2026-10-30T01:21:55.213Z
tags: [playwright, performance, http-cache, cdp, measurement]
canonical: https://blog.wooncloud.com/posts/playwright-route-disables-http-cache
---

같은 출처 iframe이 부모 페이지가 이미 받아 둔 웹폰트를 재사용하도록 바꾼 뒤, 전후를 비교하려 했습니다. 배포 전이라 Playwright로 실제 서비스에 접속하고, iframe의 HTML과 JS 요청만 `page.route()`와 `context.route()`로 가로채 로컬 빌드로 바꿔치기했습니다.

## 개선은커녕 더 느려 보였다

결과가 이상했습니다. iframe이 부모와 같은 URL의 폰트(약 2MB)를 매번 처음부터 다시 받고 있었습니다. 개선이 없었을 뿐 아니라 오히려 느려 보였고, warm(두 번째 열기)이라고 잰 값도 사실상 cold였습니다.

![route() 를 쓰면 캐시가 꺼져 warm 이 cold 와 같아지지만, CDP Fetch 로 가로채면 캐시가 살아 있어 warm 이 304 로 짧게 끝난다.](/images/posts/playwright-route-disables-http-cache/7f91404b-cba3-4387-84f1-d79175081342.webp)

원인은 코드가 아니라 측정 장치였습니다. **Playwright는 route를 하나라도 등록하면 그 컨텍스트의 HTTP 캐시를 끕니다.** 가로채지 않은 요청까지 전부요.

그러니 "캐시를 공유해서 빨라진다"는 가설은 이 방식으로는 원리적으로 측정할 수 없습니다.

![page.route() 를 등록하면 HTTP 캐시가 꺼져 폰트를 매번 새로 받아 warm 이 cold 와 같아지고, CDP Fetch 로 가로채면 캐시가 유지되어 폰트가 304 재검증으로 끝난다.](/images/posts/playwright-route-disables-http-cache/03fa831d-6363-4bbf-ab8b-f481f7afeb26.svg)

## CDP Fetch 로 직접 가로채기

가로채기를 Playwright route 대신 CDP `Fetch` 도메인으로 직접 걸었습니다. 이 경우 브라우저 캐시는 그대로 살아 있습니다. 몇 가지는 신경 써야 했습니다.

- 패턴은 바꿔치기할 경로로만 좁힙니다. 나머지는 `continueRequest`로 실서버에 보냅니다.
- 로컬 응답에는 크기에 비례한 지연(TTFB + 바이트/대역)을 넣습니다. 그러지 않으면 번들 크기 차이가 0ms로 보입니다.
- 해시가 붙은 자산은 같은 실행 안에서 두 번째 요청부터 지연을 0으로 둬 캐시 적중을 흉내 냅니다. CDP로 fulfill한 응답은 HTTP 캐시에 저장되지 않기 때문입니다.
- 비교 대상끼리 같은 자원을 같은 경로로 보냅니다. 한쪽 폰트는 로컬 fulfill(대역 경쟁 없음)로, 다른 쪽은 실네트워크로 보내면 공정하지 않습니다.

```js
const cdp = await context.newCDPSession(page);
await cdp.send("Fetch.enable", {
  patterns: [{ urlPattern: "https://example.com/app/*", requestStage: "Request" }],
});
cdp.on("Fetch.requestPaused", async (ev) => {
  if (!shouldReplace(ev.request.url)) {
    return cdp.send("Fetch.continueRequest", { requestId: ev.requestId });
  }
  const body = readLocalBuild(ev.request.url);
  await delay(25 + wireSize(body) / 8000); // TTFB + 대역 보정
  await cdp.send("Fetch.fulfillRequest", {
    requestId: ev.requestId,
    responseCode: 200,
    responseHeaders: [{ name: "content-type", value: "text/javascript" }],
    body: body.toString("base64"),
  });
});
```

바꾼 뒤에는 폰트가 304 재검증(수백 바이트)으로 끝나는 게 보였고, cold 중앙값이 약 절반으로 줄었습니다.

## 다음부터는

캐시나 재사용 효과를 재는 실험이라면 route를 쓰는 순간 결과를 믿지 않기로 했습니다. warm 값이 cold와 비슷하게 나오면 측정 장치부터 의심하고, 요청 로그에서 `fromCache`와 304 여부를 직접 확인한 뒤에 숫자를 봅니다.

## 참고

- https://playwright.dev/docs/api/class-page#page-route
- https://chromedevtools.github.io/devtools-protocol/tot/Fetch/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
