2025-08-02 00:08
최근 네이버 Whale 브라우저의 User Agent를 분석하다가 흥미로운 발견을 했습니다.
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) 'Chrome/136.0.0.0', 'Whale/4.32.315.22', 'Safari/537.36'분명히 Whale은 Blink 엔진을 사용하는데, 왜 User Agent에는 AppleWebKit이 들어있을까요? 이것은 웹 브라우저 역사상 가장 흥미로운 “호환성의 거짓말”과 관련이 있습니다.
모든 것은 KDE 프로젝트의 KHTML 엔진에서 시작되었습니다.
1998년: KHTML 렌더링 엔진 개발 (KDE 프로젝트)Apple이 Safari 브라우저를 위해 KHTML을 포크하여 WebKit을 만들었습니다.
KHTML → WebKit (Apple이 포크)Google이 WebKit 기반으로 Chrome을 개발했습니다. 이때까지는 Chrome도 진짜 WebKit을 사용했습니다.
WebKit → Chrome (Google이 WebKit 기반으로 개발)Google이 멀티프로세스 아키텍처와 성능 최적화를 위해 WebKit에서 Blink를 포크했습니다.
WebKit → Blink (Google이 포크)네이버 Whale의 실제 구조:
User Agent에 표시되는 내용:
많은 웹사이트들이 User Agent 문자열로 브라우저를 감지합니다:
// 잘못된 예시 - 많은 웹사이트가 이렇게 함
if (userAgent.includes('WebKit')) {
// Safari/Chrome 스타일 CSS 적용
applyWebKitStyles();
} else {
// 다른 브라우저 스타일 적용
applyOtherStyles();
}만약 Blink 브라우저가 User Agent에서 WebKit을 제거한다면, 기존 웹사이트들이 제대로 동작하지 않을 수 있습니다.
Blink는 WebKit에서 포크된 엔진이므로, 근본적으로는 같은 뿌리를 가집니다. API와 기능의 상당 부분이 호환됩니다.
웹 개발자들이 복잡한 브라우저 감지 로직을 작성하지 않아도 되도록 합니다.
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edge/131.0.0.0Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 OPR/117.0.0.0모든 Chromium 기반 브라우저가 동일하게 AppleWebKit/537.36을 포함합니다!
// 이렇게 하면 안 됩니다!
if (userAgent.includes('WebKit')) {
console.log('Safari 브라우저입니다'); // 틀림!
}위 코드는 Chrome, Edge, Whale 등 모든 Blink 브라우저에서도 true를 반환합니다.
function detectBrowser() {
const ua = navigator.userAgent;
if (ua.includes('Whale/')) {
return { name: 'Whale', engine: 'Blink' };
} else if (ua.includes('Edge/')) {
return { name: 'Edge', engine: 'Blink' };
} else if (ua.includes('Chrome/')) {
return { name: 'Chrome', engine: 'Blink' };
} else if (ua.includes('Safari/') && !ua.includes('Chrome/')) {
return { name: 'Safari', engine: 'WebKit' };
} else if (ua.includes('Firefox/')) {
return { name: 'Firefox', engine: 'Gecko' };
}
return { name: 'Unknown', engine: 'Unknown' };
}User Agent 감지보다는 **기능 감지(Feature Detection)**를 우선 사용하세요:
// async/await 지원 체크
function supportsAsyncAwait() {
try {
new Function('return (async function(){})()');
return true;
} catch (e) {
return false;
}
}
// Chromium 기반 브라우저 통합 감지
function isChromiumBased() {
const ua = navigator.userAgent;
return ua.includes('Chrome/') ||
ua.includes('Whale/') ||
ua.includes('Edge/') ||
ua.includes('Opera/');
}
// 실제 엔진 감지
function getActualEngine() {
if (isChromiumBased()) {
return 'Blink';
} else if (navigator.userAgent.includes('Safari/') &&
!navigator.userAgent.includes('Chrome/')) {
return 'WebKit';
} else if (navigator.userAgent.includes('Firefox/')) {
return 'Gecko';
}
return 'Unknown';
}네이버 Whale은 Blink 엔진을 사용하므로 Chrome과 동일한 모든 기능을 지원합니다:
// 기능 감지 + 폴백 패턴
function createAsyncFunction() {
if (supportsAsyncAwait()) {
return async function fetchData() {
try {
const response = await fetch('/api/data');
return await response.json();
} catch (error) {
console.error('Error:', error);
}
};
} else {
// Promise 폴백
return function fetchData() {
return fetch('/api/data')
.then(response => response.json())
.catch(error => console.error('Error:', error));
};
}
}
// 사용
const fetchData = createAsyncFunction();
fetchData().then(data => {
console.log('Data:', data);
});AppleWebKit/537.36StatCounter 데이터에 따르면 한국에서의 브라우저 점유율:
네이버 Whale은 한국에서 9.4%의 점유율을 가진 무시할 수 없는 브라우저입니다. 다행히 Chromium 기반이므로 Chrome과 동일하게 개발하면 됩니다.
typeof, in 연산자, try-catch를 활용이제 Whale 브라우저의 User Agent에 WebKit이 들어있는 이유를 아시겠죠? 이것은 웹의 역사와 호환성을 위한 선택이었습니다. 개발자로서는 이런 “거짓말” 때문에 혼란스러울 수 있지만, 기능 감지를 우선하는 모던한 개발 방식을 사용한다면 큰 문제가 되지 않습니다.
이 글이 도움이 되셨다면 댓글로 의견을 남겨주세요! 브라우저 호환성과 관련된 다른 궁금한 점이 있으시면 언제든 질문해주세요. 🚀