들어가며
프로젝트를 진행하는 과정에서 PC 브라우저를 구분해줘야 할 필요가 생겼는데, Edge 브라우저까지 고려해서 정리해주면 좋겠다 싶어서 시간을 내서 각 브라우저별 UserAgent 를 리스팅하고 이를 바탕으로 브라우저 구별 스크립트를 짜봤다.
브라우저별 UserAgent
주요 브라우저인 Edge, IE, Chrome, Safari, FireFox, Opera 의 UserAgent 패턴을 찾기위해 아래와 같이 한 두개씩 리스팅했다. 완벽하진 않겠지만 아래의 리스트를 바탕으로 패턴을 찾는다면 대부분의 케이스에서 브라우저를 구별할 수 있을 것이다.
Edge
Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136
IE11
Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
IE10
Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 7.0; InfoPath.3; .NET CLR 3.1.40767; Trident/6.0; en-IN)
Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
IE9
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; Zune 4.7)
IE8
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.2; SV1; .NET CLR 3.3.69573; WOW64; en-US)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)
IE7
Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)
Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)
IE6
Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)
Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1)
Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Chrome
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36
Safari
Mozilla/5.0 (Windows; U; Windows NT 6.1; ko-KR) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4
파이어폭스
Mozilla/5.0 (Windows; U; Windows NT 6.1; ko; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 IPMS/A640400A-14D460801A1-000000426571
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0
오페라
Opera/9.80 (Windows NT 6.1; U; ko) Presto/2.6.30 Version/10.62
위의 브라우저별 UserAgent 를 기준으로 할때, IE -> 엣지 -> 크롬 -> 사파리 -> 파이어폭스 -> 오페라 순으로 브라우저를 체크해주면 브라우저를 정확하게 구분해줄 수 있음을 알 수 있다. 사실 IE, 파이어폭스, 오페라는 순서에 관계없고 IE는 점유율을 생각해서 처음에 체크해주는 것이 유리할 것으로 판단했다.
엣지가 크롬이나 사파리보다 먼저인 것은 엣지의 UserAgent 에는 Chrome 과 Safari 라는 문구가 모두 포함되어 있기 때문이다. 마찬가지로 크롬에도 Safari가 포함되어 있기 때문에 Safari 보다 앞에서 체크해야 한다. 또 IE 의 경우 11부터 MSIE 라는 문구가 빠지고 이전 버전의 경우 Trident 가 누락될 수 있기 때문에 이 두가지 케이스를 모두 체크해줄 필요가 있다.
Switch 문의 정규식
어쩌면 안티패턴일지도 모르겠지만, Switch문 안에 정규식으로 case 를 작성해서 브라우저를 구별하는 스크립트를 작성했다. if/else 로 하는것보다 성능상 나아지는 것도 떨어지는 것도 없지만 switch문에 정규식을 쓰는것은 뭔가 바람직하지 않은 느낌이 든다. (사실 switch문의 정규식때문에 이 포스팅을 작성하고 있다..)
var browserName = undefined; var userAgent = navigator.userAgent; switch (true) { case /Trident|MSIE/.test(userAgent): browserName = 'ie'; break; case /Edge/.test(userAgent): browserName = 'edge'; break; case /Chrome/.test(userAgent): browserName = 'chrome'; break; case /Safari/.test(userAgent): browserName = 'safari'; break; case /Firefox/.test(userAgent): browserName = 'firefox'; break; case /Opera/.test(userAgent): browserName = 'opera'; break; default: browserName = 'unknown'; }
Switch 문 안의 정규식.. 뭔가 나쁜 짓을 한 것 같은 기분이 들지만, 잘 동작하고 실제 성능상으로도 if/else 로 정규식 비교를 한 것과 차이가 없다. 성능상의 차이가 있을까 싶어 염려한 누군가가 jsperf 에 복잡한 케이스는 아니지만 간단한 switch 문과 정규식을 사용한 if/else , switch 문의 비교를 해놓았다.
https://jsperf.com/switch-vs-if-else-and-regex
단순 비교만 하는 switch 문이 가장 성능이 좋고 if/else 로 정규식을 비교하는 것과 switch 문에 정규식을 사용하는 것은 성능상 큰 차이가 없음을 알 수 있다. 물론 그렇다고 이렇게 switch 문 안에서 정규식을 사용하는 것을 장려하는 것은 아니다. 다만 이런 식으로도 사용 가능한 자바스크립트의 유연함에 재미있다는 생각이 들었다. (마무리하고 있는 지금.. 뭔가 약간 심심한 글이 되어 버린 기분이..)
참조
http://www.useragentstring.com/
http://jsperf.com/switch-vs-if-else-and-regex/