User-Agent Client Hints์ ๋์ , UA ํ๋ฆฌ์ง์ ๋๋นํ๋ผ
User-Agent Client Hints์ ๋์ , UA ํ๋ฆฌ์ง์ ๋๋นํ๋ผ ๊ด๋ จ
์ด ๊ธ์์๋ ํด๋ผ์ด์ธํธ ์ ์ฅ์์ User-Agent Client Hints๋ฅผ ๋ค๋ฃน๋๋ค.
์ง๊ธ๊น์ง ์น ์๋น์ค๋ User-Agent HTTP ํค๋์ ํฌํจ๋ User-Agent string์์ ๋ธ๋ผ์ฐ์ , OS, ์ฌ์ฉ์์ ๊ธฐ๊ธฐ ์ ๋ณด ๋ฑ ์ฌ์ฉ์ ์์ด์ ํธ ์ ๋ณด๋ฅผ ์ป์ ์ ์์์ต๋๋ค. User-Agent string์ ์ด์ฉํ๋ ์ด์ ๋ ์ฃผ๋ก ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํน์ ๋ฒ์ ์ ๋ฒ๊ทธ
- OS์ ๋์ ์ฐจ์ด
- ๋ฒ์ ์ ๋ฐ๋ฅธ ๋์ ์ฐจ์ด
- ์ฌ์ฉ์ ์์ด์ ํธ์ ๋ฐ๋ผ ๋ณด์ฌ์ค ์ฝํ ์ธ ํ์
์ฐ๋ฆฌ๋ ์์ ๊ฐ์ ๋ค์ํ ์ด์ ๋ก User-Agent string์ ์ฌ์ฉํด ์์ง๋ง User-Agent string์๋ ๋ง์ ์ํธ๋กํผ(์ ๋ณด๋)๊ฐ ๋ด๊ฒจ ์์ด ๊ฐ์ธ์ ๋ณด ์นจํด ๋ฌธ์ ๊ฐ ์์ ์ ์์ต๋๋ค.
๊ทธ๋์ Chrome์ ๊ฐ์ธ์ ๋ณด ๋ณดํธ๋ฅผ ์ํ ์๋๋ฐ์ค ํ๋ก์ ํธ ์ค Client Hints ๋์ ์ ์๋ํ์ต๋๋ค. Client Hints๋ฅผ ์ฝ๊ฒ ๋งํ์๋ฉด ํด๋ผ์ด์ธํธ ๋ฐ ์์ด์ ํธ์ ์ ๋ณด๋ผ๊ณ ํ ์ ์์ผ๋ฉฐ ๊ฐ์ ธ์ฌ ์ ๋ณด๋ฅผ ๋ช ์ํฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์๋ ์๋ฒ ๋ฐ ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ค ์ ๋ณด๋ฅผ ์๊ตฌํ๋์ง ์ ์ ์์ต๋๋ค. ์ง๊ธ๊น์ง์ Client Hints ๊ด๋ จ Chrome ๋ฆด๋ฆฌ์ฆ ์ฌํญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Chrome 46 - HTTP Client Hints ์คํ์ ๋์
- Chrome 77 - Freeze-User-Agent ํ๋๊ทธ ์ถ๊ฐ
- Chrome 82, 83 (2020.05) - User-Agent Client Hints ์คํ์ ๋์
- Chrome 84 (2020.07) - User-Agent Client Hints ์ธํฐํ์ด์ค ๋ณ๊ฒฝ
์ด ๊ธ์์๋ ์ด์ ๋ฐ๋ผ ์์ผ๋ก ์ด๋ค ๋ณํ๊ฐ ์์์ง, ์ด ๋ณํ์ ์ด๋ป๊ฒ ๋์ํด์ผ ํ ์ง ์์๋ณด๊ฒ ์ต๋๋ค.
UA ํ๋ฆฌ์ง
Chrome 83๋ถํฐ User-Agent Client Hints๊ฐ ์คํ์ ์ผ๋ก ๋์ ๋์๊ณ ๊ฐ์ฅ ํฐ ์ด์๋ ๋ฐ๋ก User-Agent string ํ๋ฆฌ์ง(์ดํ UA ํ๋ฆฌ์ง)์ด๋ค. UA ํ๋ฆฌ์ง์ผ๋ก ๋ฌ๋ผ์ง๋ ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ๋ค์ ์์ฑ๊ฐ์ด ๊ณ ์ ๋๋ค.
navigator.userAgent
navigator.appVersion
navigator.platform
(Android Chrome์์๋ Linux armv8l์ผ๋ก ๊ณ ์ )navigator.productSub
navigator.vendor
- Chrome์์ ์๋๋ก์ด๋๋ฅผ ์ ์ธํ ๋ชจ๋ ์ด์์ฒด์ ๋ ์๋์ฐ 10์ผ๋ก ๋ณํ๋ค.
- ๋๊ธฐ ๋ฐฉ์์ผ๋ก OS ์ด๋ฆ, OS ๋ฒ์ , ๋ชจ๋ธ๋ช ์ ์ ์ ์๋ค.
navigator.userAgent
๋์navigator.userAgentData
์ ์ฌ์ฉํด์ผ ํ๋ค.- ๋ธ๋ผ์ฐ์ ๋ฒ์ ์ ๋ฉ์ด์ ๋ฒ์ ๋ง ๋ํ๋๋ค.
- OS ์ด๋ฆ, ๋ฒ์ , ๋ชจ๋ธ๋ช , ๋ธ๋ผ์ฐ์ ์ ํ๋ฒ์ ์ ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ ์ ์๋ค.
UA ํ๋ฆฌ์ง์ ๋ค์ ํ๋๊ทธ๋ฅผ ํ์ฑํํ๋ฉด ํ ์คํธํ ์ ์๋ค.
chrome://flags/#enable-experimental-web-platform-features
chrome://flags/#freeze-user-agent
UA ํ๋ฆฌ์ง ํ
์คํธ ๊ฒฐ๊ณผ navigator.userAgent
๋ฅผ ์ฌ์ฉํ์ฌ ์ป์ User-Agent string ๊ฐ์ ๋ค์๊ณผ ๊ฐ๋ค.
- Galaxy Z Flip, Android 10, Chrome 85.0.4183.81
- ์ :
Mozila/5.0 (Linux; Android 10; SM-F700N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Mobile Safari/537.36
- ํ:
Mozila/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.0.0 Mobile Safari/537.36
- ์ :
- Mac OS X 10.15.4, Chrome Canary 87.0.4243.0
- ์ :
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4243.0 Safari/537.36
- ํ:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.0.0 Safari/537.36
- ์ :
UA ํ๋ฆฌ์ง ๊ฒฐ๊ณผ ๊ธฐ๊ธฐ๋ช , OS์ ์ ๋ณด, ๋ธ๋ผ์ฐ์ ์ ๋ฒ์ ์ด ๋ถ๋ถ๋ช ํด์ง ๊ฒ์ ํ์ธํ ์ ์๋ค. ์์ผ๋ก User-Agent string์ ๊ณ ์ ๋ ๊ฐ์ผ๋ก ์ ๊ณตํ๊ธฐ ์ํด ๊ฐ์ ์ ์ ๋ ๊ฐ์ํด์ง ์ ์๋ค.
UA ํ๋ฆฌ์ง ๋์ ๋ฐฉ์
User-Agent Data
UA ํ๋ฆฌ์ง์ ๋์ ๋ฐฉ์์ผ๋ก User-Agent string์ ์ธ๋ถํํด Object ํ์์ผ๋ก ๋ํ๋ธ User-Agent Data๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ธํฐํ์ด์ค๋ ๋ค์๊ณผ ๊ฐ๋ค.
dictionary NavigatorUABrandVersion {
DOMString brand;
DOMString version;
};
dictionary UADataValues {
DOMString platform;
DOMString platformVersion;
DOMString architecture;
DOMString model;
DOMString uaFullVersion;
};
[Exposed=(Window,Worker)]
interface NavigatorUAData {
readonly attribute FrozenArray>NavigatorUABrandVersion> brands;
readonly attribute boolean mobile;
Promise>UADataValues> getHighEntropyValues(sequence>DOMString> hints);
};
interface mixin NavigatorUA {
[SecureContext] readonly attribute NavigatorUAData userAgentData;
};
Navigator includes NavigatorUA;
WorkerNavigator includes NavigatorUA;
navigator.userAgentData
์ ์ ๊ทผํ๋ฉด brands
(84 ์ด์ ๋ฒ์ ์์๋ uaList
)๊ณผ mobile
์์ฑ์ด ์์ผ๋ฉฐ getHighEntropyValues
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
brands
๋ ์ฌ์ฉ์ ์์ด์ ํธ์ ์์ ๋ช ๊ณผ ๋ฒ์ ์ ์ด๋ฆ์ด ๋ด๊ธด ๋ฆฌ์คํธ์ด๋ค. 87 ๋ฒ์ ์ ๊ธฐ์ค์ผ๋ก Chromium์ ์ฌ์ฉํ๋ ๋ธ๋ผ์ฐ์ ์์๋ ๋ธ๋ผ์ฐ์ ๋ธ๋๋, Chromium ๋ธ๋๋, GREASE ๋ธ๋๋ 3๊ฐ์ ๊ฐ์ด ์์์ ์์๋ก ์๋ค.mobile
์ ์ฌ์ฉ์ ์์ด์ ํธ์ ๊ธฐ๊ธฐ๊ฐ ๋ชจ๋ฐ์ผ์ธ์ง๋ฅผ ๋ํ๋ด๋ ๊ฐ์ด๋ค.getHighEntropyValues
๋ฉ์๋๋ ๋์ ์ํธ๋กํผ์ ํด๋นํ๋ ๊ฐ์ ๊ฐ์ ธ์จ๋ค.brands
(๋ธ๋ผ์ฐ์ ์ด๋ฆ๊ณผ ๋ฉ์ด์ ๋ฒ์ )์mobile
์ ๋ฎ์ ์ํธ๋กํผ๋ก ๋ถ๋ฅ๋๊ธฐ ๋๋ฌธ์ ๋๊ธฐ ๋ฐฉ์์ผ๋ก ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์์ง๋ง ๊ทธ ์ธ ์ ๋ณด๋ ๋์ ์ํธ๋กํผ๋ก ๋ถ๋ฅ๋์ดgetHighEntropyValues
๋ฉ์๋๋ก ๊ฐ์ ธ์์ผ ํ๋ค. ๋ํ User-Agent string์ฒ๋ผ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ ์๋๋ผ ์์ ์๊ฒ ํ์ํ ์ ๋ณด๋ง ๊ฐ์ ธ์ฌ ์ ์๋ค.
navigator.userAgentData.getHighEntropyValues([
"architecture",
"model",
"platform",
"platformVersion",
"uaFullVersion",
]).then(<span class="hljs-function"><span class="hljs-params">info => {
<span class="hljs-built_in">console.log(info);
});
์์ง์ Editor's draft ์ํ์ด๋ฉฐ Chrome 85์์๋ ๊ถํ ์์ฒญ ํ๋กฌํํธ๊ฐ ๋ํ๋์ง ์๋๋ค. ํ์ง๋ง ์ฌ์ฉ์ ๊ถํ์ด ํ์ํ ๋ฉ์๋์ด๊ธฐ ๋๋ฌธ์ ์ถํ์๋ ๊ถํ ์์ฒญ ํ๋กฌํํธ๊ฐ ๋ํ๋ ์ ์๊ณ ์ฌ์ฉ์๋ค์ ์ด ์ฌ์ดํธ์์ ์ด๋ค ์ ๋ณด๋ฅผ ์์งํ๋์ง ์ ์ ์๊ฒ ๋๋ค.
navigator.userAgentData.getHighEntropyValues
๋ฅผ ํตํด ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ฉด ๊ธฐ์กด User-Agent string์ผ๋ก ์ป์ ์ ๋ณด์ ๋์ผํ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ค. ํ์ง๋ง ๋ชจ๋ ์ฝ๋๋ฅผ ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ๋ฐ๊พธ๊ธฐ ์ด๋ ค์ธ๋ฟ๋๋ฌ ๋ค์ ์ฝ๋์ ๊ฐ์ด ์์๋ก ์ฌ์ฉํ๋ ์ฌ๋๋ ์์ ๊ฒ์ด๋ค.
const userAgent = navigator.userAgent;
// check Mac
export const isMac = userAgent.indexOf("Mac") > -1;
// check iOS
export const isIOS = (isMac || userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;
// check Chrome
export const isChrome = userAgent.indexOf("Chrome") > -1;
๋ค์ด๋ฒ ์๋น์ค๊ฐ ์ฌ์ฉํ๊ณ ์๋ agent ๋ชจ๋ @egjs/agent
(naver/egjs-agent
)๋ navigator.userAgent
๋ฅผ ํตํด ๋ธ๋ผ์ฐ์ ๋ฐ OS ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ณ ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ UA ํ๋ฆฌ์ง์ ๋ํ ๋๋น๊ฐ ํ์ํ๋ค. @egjs/agent
์์๋ navigator.userAgentData
๋ฅผ ์ด์ฉํด ์ด๋ป๊ฒ ๋ฌธ์ ์ ๋์ํ๋์ง ์์๋ณด๊ฒ ๋ค.
๋๊ธฐ ๋ฐฉ์์ ๋์ ๋ฐฉ์
๋จผ์ ๋๊ธฐ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ค๋ฉด ๊ธฐ์กด ์ฝ๋์ ํฌ๊ฒ ๋ฌ๋ผ์ง์ง ์๊ธฐ ๋๋ฌธ์ ์ต์ ์ ํด๊ฒฐ์ฑ ์ผ ๊ฒ์ด๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋๊ธฐ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ ๋ฌธ์ ๋ผ๋ฉด ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ ํ์ ๊ณ ๋ คํด์ผ ํ๋ค.
๋๊ธฐ ๋ฐฉ์์ผ๋ก ํ์ธํ ์ ์๋ ์ ๋ณด๋ ๋ค์๊ณผ ๊ฐ๋ค.
navigator.userAgentData.brands
: ๋ธ๋ผ์ฐ์ ์ ์ด๋ฆ๊ณผ ๋ฉ์ด์ ๋ฒ์ , Chromium ์ ๋ณดnavigator.userAgentData.mobile
: ๋ชจ๋ฐ์ผ ์ฌ๋ถnavigator.platform
: Android Chrome(Linux armv8l) ์ฌ๋ถ- User-Agent Client Hints๋ฅผ ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ์ OS, OS ๋ฒ์ (Chrome 84์ ์ง์ ๋ฒ์: Android 5.0 ์ด์, Mac OS X 10.10 ์ด์, ์๋์ฐ 7 ์ด์)
๋ค์์ ๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ์์ด์ ํธ ์ ๋ณด๋ฅผ ํ์ธํ๋ ์์ ์ฝ๋์ด๋ค.
import getAgent from "@egjs/agent";
const agent = getAgent();
// Android ํ์ธ
export const IS_ANDROID = agent.os.name === "android";
// ๋ธ๋ผ์ฐ์ IE11 ํ์ธ
export const IS_IE11 = agent.browser.name === "ie" && agent.browser.majorVersion === 11;
// User-Agent Client Hints๋ฅผ ์ง์ํ์ง ์๋ Android 4 ํ์ธ
export const IS_ANDROID4 = IS_ANDROID && agent.os.majorVersion === 4;
// User-Agent Client Hints๋ฅผ ์ง์ํ์ง ์๋ iOS 10 ํ์ธ
export const IS_IOS10 = agent.os.name === "ios" && agent.os.majorVersion === 10;
Safari ์ถ์ธก
.Safari(Safari 14, AppleWebkit 605 ๊ธฐ์ค)๋ ์์ง User-Agent Client Hints๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ brand ๋ฆฌ์คํธ์ ๋ฌด์จ ๊ฐ์ด ์์์ง ์ ์ ์๋ค. ๋ํ iOS ์ ์ฑ ์ ๋ฌธ์ ๋ก ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ์์ง์ ์ฌ์ฉํ๊ณ ์๋ ๊ธฐ์กด์ ๋ธ๋ผ์ฐ์ (Chrome, Whale, Edge, Firefox)๋ iOS ๋ฒ์ ์์๋ Safari๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ผ Safari์์ User-Agent Client Hints๊ฐ ๋์ ๋๋ค๋ฉด brand ๋ฆฌ์คํธ์๋ ์ด๋ค ๊ฐ์ด ์์๊น? iOS Chrome์ ๊ธฐ์ค์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ถ์ธกํ ์ ์๋ค.
- [Safari, Chrome]
- [Safari, CriOS]
- [AppleWebkit, Chrome]
- [AppleWebkit, CriOS]
- Safari ๊ธฐ๋ฐ์ด๊ณ mobile์ด๋ฉด iOS ์ด๋ค.
- Safari ๊ธฐ๋ฐ์ด๊ณ mobile์ด ์๋๋ฉด Mac ์ด๋ค.
์ฆ, ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ์์ด์ ํธ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์์ ๊ฒ์ด๋ค.
import getAgent from "@egjs/agent";
const agent = getAgent();
// iOS ์ถ์ธก ๊ฐ๋ฅ
export const IS_IOS = agent.os.name === "ios";
// MAC Safari ์ถ์ธก ๊ฐ๋ฅ
export const IS_MAC_SAFARI = agent.os.name === "mac" && agent.browser.name === "safari";
๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ ํ
๋๊ธฐ ๋ฐฉ์์ผ๋ก ํ์ธํ ์ ์๋ ์ ๋ณด๋ ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์์ด์ ํธ ๊ฐ์ ์ป์ ํ์ ์ฝ๋๊ฐ ์คํ๋์ด์ผ ํ๋ค. ๋๊ธฐ ๋ฐฉ์์ผ๋ก ํ์ธํ ์ ์๋ ์ ๋ณด๋ ๋ค์๊ณผ ๊ฐ๋ค.
- Android, iOS, Mac Safari๋ฅผ ์ ์ธํ OS ์ ๋ณด
- ํน์ OS ๋ฒ์
- ๋ธ๋ผ์ฐ์ ์ ํ๋ฒ์
import getAgent from "@egjs/agent";
const agent = getAgent();
// Windows๋ฅผ ํ์ธํ ์ ์๋ค.
export const IS_WINDOWS = agent.os.name === "window";
// Safari๋ฅผ ์ ์ธํ mac OS๋ฅผ ํ์ธํ ์ ์๋ค.
export const IS_MAC = agent.os.name === "mac";
๋ค์์ navigator.userAgentData.getHighEntropyValues
๋ฉ์๋๋ก ์ ํํ agent ๊ฐ์ ์ป์ ์ ์๋๋ก ๋ง๋ getAccurateAgent
๋น๋๊ธฐ ํจ์์ด๋ค.
import { getAccurateAgent } from "@egjs/agent";
async <span class="hljs-function">function <span class="hljs-title">start(<span class="hljs-params">) {
const agent = await getAccurateAgent();
const isWindows = agent.os.name === "window";
const isMac = agent.os.name === "mac";
}
๋ง์น๋ฉฐ
๋งค์ผ 3์ฒ๋ง ๋ช
์ด์์ด ๋ค์ด๋ฒ ์๋น์ค๋ฅผ ์ด์ฉํ๊ณ ์์ผ๋ฉฐ ๋ชจ๋ ์๋น์ค์์ @egjs/agent
๋๋ navigator.userAgent
๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ค์ด๋ฒ๋ User-Agent Client Hints ๋์
์ ์ฃผ๋ชฉํ๊ณ ์๋ค. ๊ฐ์๊ธฐ User-Agent Client Hints๊ฐ ๋์
๋๋ค๋ฉด ์๋น์ค๋ฟ๋ง ์๋๋ผ agent ๋ชจ๋์ ์ฌ์ฉํ๊ณ ์๋ Component๋ค๋ ํฐ ํ๊ฒฉ์ ์
์ ๊ฒ์ด๋ฏ๋ก ๋ค์ด๋ฒ FE Platform ํ์ User-Agent Client Hints๋ฅผ ๋ฆฌ์์นํ๊ณ @egjs/agent
๋ฅผ ํตํด ์ง์ํ๊ธฐ๋ก ํ๋ค.
User-Agent Client Hints๋ ์์ง Editor's Draft ์ํ(2020.09.18)์ด๋ฉฐ ์ธ์ ๋ ์ง ์ธํฐํ์ด์ค ๋ฐ ๋์์ด ๋ฐ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๊ณ์ ์ฃผ์ํ๊ณ ์๊ณ Chromium๋ฟ๋ง ์๋๋ผ Webkit ์ฝ๋๋ ํ์ธํ๋ฉด์ ๋น ๋ฅด๊ฒ ๋์ํ๊ณ ์ ํ๋ค. ์ฌ๋ฌ๋ถ๋ ํจ๊ป ์ค๋นํ๋ ๋ฐ ์ด ๊ธ์ด ๋์์ด ๋๊ธธ ๋ฐ๋๋ค.