퍼펫티어(혹은 헤드리스 크롬)에서 구글 폰트의 나눔 명조가 보이지 않는 문제 CSS

퍼펫티어(Puppeteer)를 이용해 스크린샷을 찍는 프로그램을 짜는 도중, 특정 한글 글꼴들이 제대로 동작하지 않는다는 것을 발견했다. 코드는 다음과 같다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <style>
        @import url(https://fonts.googleapis.com/css?family=Signika);
        @import url(https://fonts.googleapis.com/css?family=Open+Sans);
        @import url(https://fonts.googleapis.com/css?family=Nanum+Myeongjo);
        body {
            font-family: 'Signika', sans-serif;
            background-color: white;
        }
        h1 {
            font-family: 'Open Sans', sans-serif;
        }
        h2 {
            font-family: 'Nanum Myeongjo', sans-serif;
        }
    </style>
</head>
<body>
Signika Text 기본 한글
<h1>Open Sans</h1>
<h2>나눔 명조</h2>
</body>
</html>
// ...

const browser = await puppeteer.launch({
  headless: true, // 불필요하다.
  args: ['--no-sandbox', '--disable-dev-shm-usage']}
);
const page = await browser.newPage();

// ...

await page.goto(argv.source, {
    "waitUntil": ["load", "networkidle0"]
});
await page.evaluateHandle('document.fonts.ready');
await page.screenshot(settings);

// ...

실행해 보면 Signika나 Open Sans의 경우 정상 표시가 되는데, 유독 나눔 명조 글꼴만 제대로 표시되지 않았다. 나눔 고딕도 마찬가지. 반면에 헤드리스(headless) 옵션을 바꾸어 화면에 보이도록 표시하면 정상 표시 되었다. page.tracing API를 사용해 통신 내역을 확인해보니 헤드리스와 일반 상태일 때 요청 내역이 TTF와 WOFF2 파일들로 서로 달랐다. 즉 헤드리스 여부에 따라 fonts.googleapis.com 에서 반환하는 CSS 파일의 내용이 달랐던 것이다.

그런데 서버는 어떻게 헤드리스인 줄을 알았을까? 바로 User-Agent 헤더가 다르기 때문인데, 퍼펫티어 1.11.0 기준으로는 다음과 같다.

// console.log(await page.evaluate(() => navigator.userAgent)); 코드로 확인

// headless = false
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3617.0 Safari/537.36

// headless = true (default)
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/72.0.3617.0 Safari/537.36

사실 TTF라고 해서 딱히 렌더링이 안 될 이유는 없으니,  TTF 혹은 CSS 파일의 무언가가 잘못된 게 아닌가 싶지만 막연한 추측.
아무튼 page.setUserAgent 메서드를 사용해 User-Agent 헤더를 headless=false일 때의 것으로 변경하여 당장 해결은 가능하며, 추후 업스트림 패치가 이뤄져야 할 것 같다.

Leave Comments