일반 History of User Agent

황제낙엽 2011.02.22 23:45 조회 수 : 2947

navigator.userAgent에 대해 더 깊게 이해하려면, User Agent에 대한 히스토리를 알아두는 게 도움이 될 수 있다.

User-Agent 헤더의 탄생
1995년 HTML 2.0이 나오기 전까지 HTML은 표준화되지 않았다.
당시 Netscape나 Microsoft 같은 벤더들은 웹제작자들이 좀 더 풍부하게 컨텐츠를 제공할 수 있도록 각자 매력적인 기능을 추가하고 있었다. 이에 따라 다양한 브라우저가 출시되기 시작했고, 최신 브라우저는 좀 더 화려한 HTML을 제공했다.
여러 브라우저가 출시되면서 웹제작자들은 제작한 컨텐츠가 다양한 브라우저에 모두 정상적으로 보일 수 있도록 대책이 필요했다. 그 중 하나는 가장 낮은 버전의 HTML을 제공하는 것이었고, 다른 하나는 브라우저의 버전을 탐지해 서버가 브라우제 따라 적합한 컨텐츠를 내려주도록 하는 것이었다. 당시에는 브라우저에서 스크립트가 가능하지 않았기 때문에, 서버에서 브라우저를 탐지해내기 위해 User-Agent 헤더가 생기게 됐다.


"Mozilla/version",  오해의 시작
당시 브라우저는 Netscape Navigator와 Internet Explorer 뿐이었기 때문에, 브라우저를 탐지하기 위해 User Agent의 vendor와 version을 구분하는 것만으로 충분했다.

Netscape 브라우저는 "Mozilla/version" 과 같은 방식으로 코드 네임과 버전을 표시하고, 그 뒤로 추가적인 정보를 기술했다. 따라서 최초의 브라우저 탐지 기법은 userAgent에서 Mozilla/version 정보를 찾는 방식이었다.
이후의 다른 브라우저 벤더들은 자사 제품이 Netscape 브라우저의 특정 버전과 호환된다는 의미로 userAgent 정보에 Mozilla/version 을 추가했다. 실제로는 "Mozilla/version" 기반이 아니었지만 말이다.

당시 Netscape의 점유율이 가장 높았던 것을 생각하면 어쩌면 당연한 일이기도 하겠지만, 지금에 와서도 정확한 브라우저 여부를 탐지하는 것이 어려운 것은, 이 때 잘못된 이해와 표준화 되지 않은 방법으로 버전 정보를 기술한 것이 발단이 된 것으로 볼 수 있다. (호환성을 위해 지금까지도 대부분의 브라우저의 userAgent가 Mozilla/verion 의 형태로 시작한다.)


클라이언트 측 스크립트 출현
Netscape Navigator2 버전이 출시하면서 브라우저는 클라이언트 측 스크립트를 제공했고, 다른 브라우저들도 각자의 방식으로 스크립트를 구현하기 시작했다. 이제 웹제작자들은 서버측에서 User-Agent 헤더값으로 브라우저를 판별하지 않고, 클라이언트에서 바로 어떤 브라우저에서 접속했는지 찾아낼 수 있었다. 브라우저마다 스크립트의 구현 방법이 달랐기 때문에 웹제작자들은 document.images 같은 "객체 기반 탐지"로 브라우저를 구별해낼 수 있었다. 

이런 "객체 기반 탐지"가 많이 사용되었음에도 몇몇 웹자작자들은 vendor/version 접근법을 사용했다.
브라우저에서 navigator 객체도 제공했기 때문에, 이전에 서버에서 사용한 것과 같은 로직을 클라이언트에도 적용할 수 있었다. 게다가 navigator 객체에서는 appName과 appVersion을 따로 제공했기 때문에 vendor/version 값을 바로 알아낼 수 있었다.

Netscape Navigator4 버전과 Internet Explorer4 버전부터 HTML을 클라이언트에서 직접 조작할 수 있게 되었다. (DHTML)
더불어 CSS 스타일도 제공하기 시작했다. 이 시기의 브라우저에서는, 같은 벤더임에도 이전 버전과도 호환되지 않는 기능들이 추가되기도 했다.

스크립트가 그랬던 것처럼, 각 브라우저 벤더들의 DHTML 구현 방식이 달랐기 때문에, 웹제작자들은 브라우저 여부를 판단하기 위해 "객체 탐지 기법"을 주로 사용하게 됐다. 예를 들어, document.layers 객체가 존재하면 Netscape4 라는 것을, document.all 이 존재하면 Explorer4 버전이란 걸 쉽게 알 수 있었다. 물론 이 방법은 Netscape 와 Explorer 두 가지의 브라우저가 있을 때에만 가능한 일이었다.

vendor/version 으로 브라우저를 구별해내는 방법은 Gecko와 같은 다른 브라우저들이 나오면서 더 이상 의미가 없어졌다. vendor/version 단위로 브라우저를 구별해내는 방식은 제대로 작동하지도 않을 뿐더러, 유지보수하기도 어려웠다.


진짜 Mozilla/5.0 - Netscape6
Netscape6 는 최초의 Gecko 기반 상용 브라우저이며 Netscape6의 userAgent 값은 HTTP 표준을 따라,
"Mozilla/5.0 (...) Gecko/20001108" 과 같은 형태로 기술되었다.

첫 번째의 vendor/version 인 Mozilla/5.0 문구는 "Netscape6이 5세대 브라우저이며, 기존 브라우저와는 같지 않다"는 걸 나타낸다.
하지만 앞서 언급했듯이, 다른 브라우저들은 "호환성의 의미"로 첫 번째 버전을 Mozilla/5.0 이라고 표시한다.
따라서 Mozilla/5.0 구문만으로는 유일하게 Gecko라는 걸 판단할 수 없다.

두 번째 vendor/version 인 Gecko/20001108 은 Netscape6가 Gecko의 2000년 11월 8일 버전으로 구현됐다는 문구이다. 만약, 브라우저가 실제로 Gecko 기반인지를 확인하려 한다면 Gecko/CCYYMMDD 형태를 검색해보면 된다.

세 번째 vendor/version 인 Netscape6/6.0 은 이 브라우저가 Netscape6라는 걸 나타낸다. Netscape6의 경우, 벤더명에 버전명을 포함시켰기 때문에 효율적이지 않아 7버전부터는 벤더명에서 버전을 제외하여 아래와 같이 제공된다.
Mozilla/5.0 (...) Gecko/200207XX Netscape/7.0

따라서 기존의 vendor/version 기반 탐색을 Netscape4와 IE4에서만 가능했다.
document.all과 document.layers로 구분했던 객체 기반 탐지 방법도 Netscape6+ 와 IE5+ 가 출시되면서 더욱 복잡해졌다.
번호 제목 글쓴이 날짜 조회 수
246 [Gemini] ajax 와 fetch 의 차이 황제낙엽 2025.01.04 3419
245 [검토 완료] 디바이스 카메라로 촬영한 사진을 서버에 업로드하기 샘플 황제낙엽 2024.11.21 3987
244 브라우저에서 이미지를 편집(crop 등) 할 수 있는 오픈소스 Cropper.js 황제낙엽 2024.11.16 3842
243 [ChatGPT] json data 의 정렬 [1] 황제낙엽 2024.07.23 3352
242 DOMContentLoaded 이벤트와 window.onload 이벤트 황제낙엽 2024.07.15 3669
241 fetch() 사용 예제들 황제낙엽 2024.07.09 3380
240 [Copilot] Vanilla JavaScript에서 외부 스크립트 파일에 정의된 함수들을 로드 황제낙엽 2024.06.21 3758
239 [Copilot] ES6 모듈(module) 문법 황제낙엽 2024.06.21 3805
238 [Copilot] JSON 객체 내부 데이터를 순회하면서 조회하는 코드 황제낙엽 2024.06.02 3270
237 [Copilot] JavaScript로 서버에 특정 값을 POST 방식으로 전달하고 응답을 기다리지 않고 바로 종료 황제낙엽 2024.05.31 3615
236 json 데이터 내의 변수명에 prefix 로 type 표현하기 황제낙엽 2024.04.15 3361
235 fetch() 함수 사용 예제 file 황제낙엽 2023.11.23 3605
234 현재 document 의 host 와 port 를 얻는 방법 황제낙엽 2023.10.03 4209
233 (Bard) FileReader 로 여러개의 파일을 read 하는 법 file 황제낙엽 2023.08.23 3660
232 How to build a file upload service with vanilla JavaScript file 황제낙엽 2023.08.22 3715
231 (Bard) JavaScript로 JSON 배열을 작성하는 방법 황제낙엽 2023.08.21 3672
230 모바일 브라우저에서 file input element 를 이용하여 여러장의 이미지를 서버에 전송하려 할때 [1] 황제낙엽 2023.08.21 3703
229 navigator.mediaDevices 황제낙엽 2023.08.21 3798
228 Barcode Detection API 황제낙엽 2023.08.06 3854
227 정규식을 이용한 이메일 검증 스크립트 file 황제낙엽 2023.06.25 2894